Modifications in PJSUA-LIB to support multiple media streams (multiple audio and/or video) and dynamic creation of media transports. This closed #1185 and closed #1201.

1185: Dynamic creation of media transports
============================================
Done:
 - media transports are created on demand now

Todo:
 - media transport creation is still blocking


1201: Video support in PJSUA-LIB
===================================
Done:
 - call now supports N media (N audio and M video)
 - number of audio/video streams is configurable per acc
 - extra audio stream info in pjsua_call_info to support multiple audio streams
in one call
 - video subsys and ffmpeg initialization in PJSUA-LIB
 - ability to offer and create video SDP answer
 - "dq" for more than 1 audio streams
 - introducing pjsua_state and pjsua_get_state()

API change:
 - on_stream_created() and on_stream_destroyed() callbacks: changed session to
stream

Todo:
 - many others features are disabled, just search for DISABLED_FOR_TICKET_1185
macro (these have also been added to ticket #1193 (Issues & Todos)). Notable
missing features are:
      - creation of duplicate SDP m= lines for optional SRTP
      - mm.. that's it?
 - whole lot of testings

pjsua:
===============
 - Added --extra-audio and --video options. Specify these more than once and
each time an extra audio/video streams will be added. :)



git-svn-id: https://svn.pjsip.org/repos/pjproject/branches/projects/2.0-dev@3457 74dad513-b988-da41-8d7b-12977e46ad98
This commit is contained in:
Benny Prijono 2011-03-17 04:34:43 +00:00
parent 854ec1a682
commit 0bc99a9ca3
10 changed files with 1452 additions and 832 deletions

View File

@ -58,12 +58,43 @@ endif
# Additional flags
@ac_build_mak_vars@
#
# Video
# Note: there are duplicated macros in pjmedia/os-auto.mak.in (and that's not
# good!
# SDL flags
SDL_CFLAGS = @ac_sdl_cflags@
SDL_LDFLAGS = @ac_sdl_ldflags@
# FFMPEG dlags
FFMPEG_CFLAGS = @ac_ffmpeg_cflags@
FFMPEG_LDFLAGS = @ac_ffmpeg_ldflags@
# Video4Linux2
V4L2_CFLAGS = @ac_v4l2_cflags@
V4L2_LDFLAGS = @ac_v4l2_ldflags@
# QT
AC_PJMEDIA_VIDEO_HAS_QT = @ac_pjmedia_video_has_qt@
QT_CFLAGS = @ac_qt_cflags@
# iOS
IOS_CFLAGS = @ac_ios_cflags@
# PJMEDIA features exclusion
PJ_VIDEO_CFLAGS += $(SDL_CFLAGS) $(FFMPEG_CFLAGS) $(V4L2_CFLAGS) $(QT_CFLAGS) \
$(IOS_CFLAGS)
PJ_VIDEO_LDFLAGS += $(SDL_LDFLAGS) $(FFMPEG_LDFLAGS) $(V4L2_LDFLAGS)
# CFLAGS, LDFLAGS, and LIBS to be used by applications
export PJDIR := @ac_pjdir@
export APP_CC := @CC@
export APP_CXX := @CXX@
export APP_CFLAGS := -DPJ_AUTOCONF=1\
@CFLAGS@\
$(PJ_VIDEO_CFLAGS) \
-I$(PJDIR)/pjlib/include\
-I$(PJDIR)/pjlib-util/include\
-I$(PJDIR)/pjnath/include\
@ -76,6 +107,7 @@ export APP_LDFLAGS := -L$(PJDIR)/pjlib/lib\
-L$(PJDIR)/pjmedia/lib\
-L$(PJDIR)/pjsip/lib\
-L$(PJDIR)/third_party/lib\
$(PJ_VIDEO_LDFLAGS) \
@LDFLAGS@
export APP_LDLIBS := -lpjsua-$(TARGET_NAME)\
-lpjsip-ua-$(TARGET_NAME)\

View File

@ -483,6 +483,9 @@ struct pjmedia_transport
/** Transport's "virtual" function table. */
pjmedia_transport_op *op;
/** Application/user data */
void *user_data;
};
/**

View File

@ -267,7 +267,7 @@ static void usage(void)
puts (" --tls-srv-name Specify TLS server name for multihosting server");
puts ("");
puts ("Media Options:");
puts ("Audio Options:");
puts (" --add-codec=name Manually add codec (default is to enable all)");
puts (" --dis-codec=name Disable codec (can be specified multiple times)");
puts (" --clock-rate=N Override conference bridge clock rate");
@ -301,6 +301,11 @@ static void usage(void)
puts (" Specify N=0 for instant close when unused.");
puts (" --no-tones Disable audible tones");
puts (" --jb-max-size Specify jitter buffer maximum size, in frames (default=-1)");
puts (" --extra-audio Add one more audio stream");
puts ("");
puts ("Video Options:");
puts (" --video Enable video");
puts ("");
puts ("Media Transport Options:");
@ -540,7 +545,8 @@ static pj_status_t parse_args(int argc, char *argv[],
#endif
OPT_AUTO_UPDATE_NAT,OPT_USE_COMPACT_FORM,OPT_DIS_CODEC,
OPT_NO_FORCE_LR,
OPT_TIMER, OPT_TIMER_SE, OPT_TIMER_MIN_SE
OPT_TIMER, OPT_TIMER_SE, OPT_TIMER_MIN_SE,
OPT_VIDEO, OPT_EXTRA_AUDIO
};
struct pj_getopt_option long_options[] = {
{ "config-file",1, 0, OPT_CONFIG_FILE},
@ -659,6 +665,8 @@ static pj_status_t parse_args(int argc, char *argv[],
{ "timer-se", 1, 0, OPT_TIMER_SE},
{ "timer-min-se", 1, 0, OPT_TIMER_MIN_SE},
{ "outb-rid", 1, 0, OPT_OUTB_RID},
{ "video", 0, 0, OPT_VIDEO},
{ "extra-audio",0, 0, OPT_EXTRA_AUDIO},
{ NULL, 0, 0, 0}
};
pj_status_t status;
@ -1416,6 +1424,12 @@ static pj_status_t parse_args(int argc, char *argv[],
cfg->udp_cfg.qos_params.flags = PJ_QOS_PARAM_HAS_DSCP;
cfg->udp_cfg.qos_params.dscp_val = 0x18;
break;
case OPT_VIDEO:
++cur_acc->max_video_cnt;
break;
case OPT_EXTRA_AUDIO:
++cur_acc->max_audio_cnt;
break;
default:
PJ_LOG(1,(THIS_FILE,
"Argument \"%s\" is not valid. Use --help to see help",
@ -1660,6 +1674,14 @@ static void write_account_settings(int acc_index, pj_str_t *result)
/* MWI */
if (acc_cfg->mwi_enabled)
pj_strcat2(result, "--mwi\n");
/* Video & extra audio */
for (i=0; i<acc_cfg->max_video_cnt; ++i) {
pj_strcat2(result, "--video\n");
}
for (i=1; i<acc_cfg->max_audio_cnt; ++i) {
pj_strcat2(result, "--extra-audio\n");
}
}
@ -3891,6 +3913,8 @@ void console_app_main(const pj_str_t *uri_to_call)
acc_cfg.cred_info[0].data_type = 0;
acc_cfg.cred_info[0].data = pj_str(passwd);
acc_cfg.rtp_cfg = app_config.rtp_cfg;
status = pjsua_acc_add(&acc_cfg, PJ_TRUE, NULL);
if (status != PJ_SUCCESS) {
pjsua_perror(THIS_FILE, "Error adding new account", status);
@ -4928,6 +4952,7 @@ pj_status_t app_init(int argc, char *argv[])
/* Add accounts */
for (i=0; i<app_config.acc_cnt; ++i) {
app_config.acc_cfg[i].rtp_cfg = app_config.rtp_cfg;
status = pjsua_acc_add(&app_config.acc_cfg[i], PJ_TRUE, NULL);
if (status != PJ_SUCCESS)
goto on_error;
@ -4959,8 +4984,10 @@ pj_status_t app_init(int argc, char *argv[])
#else
if (app_config.ipv6)
status = create_ipv6_media_transports();
#if DISABLED_FOR_TICKET_1185
else
status = pjsua_media_transports_create(&app_config.rtp_cfg);
#endif
#endif
if (status != PJ_SUCCESS)
goto on_error;
@ -5295,6 +5322,10 @@ static pj_status_t create_ipv6_media_transports(void)
}
}
#if DISABLED_FOR_TICKET_1185
return pjsua_media_transports_attach(tp, i, PJ_TRUE);
#else
return PJ_ENOTSUP;
#endif
}

View File

@ -76,7 +76,7 @@ export PJSUA_LIB_SRCDIR = ../src/pjsua-lib
export PJSUA_LIB_OBJS += $(OS_OBJS) $(M_OBJS) $(CC_OBJS) $(HOST_OBJS) \
pjsua_acc.o pjsua_call.o pjsua_core.o \
pjsua_im.o pjsua_media.o pjsua_pres.o
export PJSUA_LIB_CFLAGS += $(_CFLAGS)
export PJSUA_LIB_CFLAGS += $(_CFLAGS) $(PJ_VIDEO_CFLAGS)
export CC_OUT CC AR RANLIB HOST_MV HOST_RM HOST_RMDIR HOST_MKDIR OBJEXT LD LDOUT

View File

@ -250,6 +250,9 @@ PJ_BEGIN_DECL
/** Constant to identify invalid ID for all sorts of IDs. */
#define PJSUA_INVALID_ID (-1)
/** Disabled features temporarily for media reorganization */
#define DISABLED_FOR_TICKET_1185 0
/** Call identification */
typedef int pjsua_call_id;
@ -282,8 +285,6 @@ typedef struct pjsua_msg_data pjsua_msg_data;
# define PJSUA_ACC_MAX_PROXIES 8
#endif
#if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0)
/**
* Default value of SRTP mode usage. Valid values are PJMEDIA_SRTP_DISABLED,
* PJMEDIA_SRTP_OPTIONAL, and PJMEDIA_SRTP_MANDATORY.
@ -303,8 +304,6 @@ typedef struct pjsua_msg_data pjsua_msg_data;
#define PJSUA_DEFAULT_SRTP_SECURE_SIGNALING 1
#endif
#endif
/**
* Controls whether PJSUA-LIB should add ICE media feature tag
* parameter (the ";+sip.ice" parameter) to Contact header if ICE
@ -326,6 +325,44 @@ typedef struct pjsua_msg_data pjsua_msg_data;
#endif
/**
* This enumeration represents pjsua state.
*/
typedef enum pjsua_state
{
/**
* The library has not been initialized.
*/
PJSUA_STATE_NULL,
/**
* After pjsua_create() is called but before pjsua_init() is called.
*/
PJSUA_STATE_CREATED,
/**
* After pjsua_init() is called but before pjsua_start() is called.
*/
PJSUA_STATE_INIT,
/**
* After pjsua_start() is called but before everything is running.
*/
PJSUA_STATE_STARTING,
/**
* After pjsua_start() is called and before pjsua_destroy() is called.
*/
PJSUA_STATE_RUNNING,
/**
* After pjsua_destroy() is called but before the function returns.
*/
PJSUA_STATE_CLOSING
} pjsua_state;
/**
* Logging configuration, which can be (optionally) specified when calling
* #pjsua_init(). Application must call #pjsua_logging_config_default() to
@ -483,7 +520,7 @@ typedef struct pjsua_callback
* media port then will be added to the conference bridge instead.
*
* @param call_id Call identification.
* @param sess Media session for the call.
* @param strm Media stream.
* @param stream_idx Stream index in the media session.
* @param p_port On input, it specifies the media port of the
* stream. Application may modify this pointer to
@ -491,7 +528,7 @@ typedef struct pjsua_callback
* to the conference bridge.
*/
void (*on_stream_created)(pjsua_call_id call_id,
pjmedia_session *sess,
pjmedia_stream *strm,
unsigned stream_idx,
pjmedia_port **p_port);
@ -500,11 +537,11 @@ typedef struct pjsua_callback
* conference bridge and about to be destroyed.
*
* @param call_id Call identification.
* @param sess Media session for the call.
* @param strm Media stream.
* @param stream_idx Stream index in the media session.
*/
void (*on_stream_destroyed)(pjsua_call_id call_id,
pjmedia_session *sess,
pjmedia_stream *strm,
unsigned stream_idx);
/**
@ -1154,7 +1191,6 @@ typedef struct pjsua_config
*/
pj_str_t user_agent;
#if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0)
/**
* Specify default value of secure media transport usage.
* Valid values are PJMEDIA_SRTP_DISABLED, PJMEDIA_SRTP_OPTIONAL, and
@ -1184,15 +1220,14 @@ typedef struct pjsua_config
int srtp_secure_signaling;
/**
* Specify whether SRTP in PJMEDIA_SRTP_OPTIONAL mode should compose
* Specify whether SRTP in PJMEDIA_SRTP_OPTIONAL mode should compose
* duplicated media in SDP offer, i.e: unsecured and secured version.
* Otherwise, the SDP media will be composed as unsecured media but
* Otherwise, the SDP media will be composed as unsecured media but
* with SDP "crypto" attribute.
*
* Default: PJ_FALSE
*/
pj_bool_t srtp_optional_dup_offer;
#endif
/**
* Disconnect other call legs when more than one 2xx responses for
@ -1352,6 +1387,14 @@ PJ_DECL(pj_status_t) pjsua_start(void);
PJ_DECL(pj_status_t) pjsua_destroy(void);
/**
* Retrieve pjsua state.
*
* @return pjsua state.
*/
PJ_DECL(pjsua_state) pjsua_get_state(void);
/**
* Poll pjsua for events, and if necessary block the caller thread for
* the specified maximum interval (in miliseconds).
@ -2093,7 +2136,6 @@ typedef enum pjsua_call_hold_type
# define PJSUA_CALL_HOLD_TYPE_DEFAULT PJSUA_CALL_HOLD_TYPE_RFC3264
#endif
/**
* This structure describes account configuration to be specified when
* adding a new account with #pjsua_acc_add(). Application MUST initialize
@ -2384,7 +2426,29 @@ typedef struct pjsua_acc_config
*/
pj_str_t ka_data;
#if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0)
/**
* Maximum number of simultaneous active audio streams to be allowed
* for calls on this account. Setting this to zero will disable audio
* in calls on this account.
*
* Default: 1
*/
unsigned max_audio_cnt;
/**
* Maximum number of simultaneous active video streams to be allowed
* for calls on this account. Setting this to zero will disable video
* in calls on this account.
*
* Default: 0
*/
unsigned max_video_cnt;
/**
* Media transport config.
*/
pjsua_transport_config rtp_cfg;
/**
* Specify whether secure media transport should be used for this account.
* Valid values are PJMEDIA_SRTP_DISABLED, PJMEDIA_SRTP_OPTIONAL, and
@ -2408,15 +2472,14 @@ typedef struct pjsua_acc_config
int srtp_secure_signaling;
/**
* Specify whether SRTP in PJMEDIA_SRTP_OPTIONAL mode should compose
* Specify whether SRTP in PJMEDIA_SRTP_OPTIONAL mode should compose
* duplicated media in SDP offer, i.e: unsecured and secured version.
* Otherwise, the SDP media will be composed as unsecured media but
* Otherwise, the SDP media will be composed as unsecured media but
* with SDP "crypto" attribute.
*
* Default: PJ_FALSE
*/
pj_bool_t srtp_optional_dup_offer;
#endif
/**
* Specify interval of auto registration retry upon registration failure
@ -2920,19 +2983,29 @@ PJ_DECL(pj_status_t) pjsua_acc_set_transport(pjsua_acc_id acc_id,
*/
typedef enum pjsua_call_media_status
{
/** Call currently has no media */
/**
* Call currently has no media, or the media is not used.
*/
PJSUA_CALL_MEDIA_NONE,
/** The media is active */
/**
* The media is active
*/
PJSUA_CALL_MEDIA_ACTIVE,
/** The media is currently put on hold by local endpoint */
/**
* The media is currently put on hold by local endpoint
*/
PJSUA_CALL_MEDIA_LOCAL_HOLD,
/** The media is currently put on hold by remote endpoint */
/**
* The media is currently put on hold by remote endpoint
*/
PJSUA_CALL_MEDIA_REMOTE_HOLD,
/** The media has reported error (e.g. ICE negotiation) */
/**
* The media has reported error (e.g. ICE negotiation)
*/
PJSUA_CALL_MEDIA_ERROR
} pjsua_call_media_status;
@ -2982,12 +3055,32 @@ typedef struct pjsua_call_info
/** Call media status. */
pjsua_call_media_status media_status;
/** Media direction */
/** Number of active audio streams in this call */
unsigned audio_cnt;
/** Media direction of the first audio stream. */
pjmedia_dir media_dir;
/** The conference port number for the call */
/** The conference port number for the first audio stream. */
pjsua_conf_port_id conf_slot;
/** Array of audio media stream information */
struct
{
/** Media index in SDP. */
unsigned index;
/** Call media status. */
pjsua_call_media_status media_status;
/** Media direction. */
pjmedia_dir media_dir;
/** The conference port number for the call. */
pjsua_conf_port_id conf_slot;
} audio[4];
/** Up-to-date call connected duration (zero when call is not
* established)
*/
@ -3082,6 +3175,7 @@ PJ_DECL(pj_bool_t) pjsua_call_is_active(pjsua_call_id call_id);
PJ_DECL(pj_bool_t) pjsua_call_has_media(pjsua_call_id call_id);
#if DISABLED_FOR_TICKET_1185
/**
* Retrieve the media session associated with this call. Note that the media
* session may not be available depending on the current call's media status
@ -3095,7 +3189,6 @@ PJ_DECL(pj_bool_t) pjsua_call_has_media(pjsua_call_id call_id);
*/
PJ_DECL(pjmedia_session*) pjsua_call_get_media_session(pjsua_call_id call_id);
/**
* Retrieve the media transport instance that is used for this call.
* Application may use the media transport to query more detailed information
@ -3106,7 +3199,7 @@ PJ_DECL(pjmedia_session*) pjsua_call_get_media_session(pjsua_call_id call_id);
* @return Call media transport.
*/
PJ_DECL(pjmedia_transport*) pjsua_call_get_media_transport(pjsua_call_id cid);
#endif /* DISABLED_FOR_TICKET_1185 */
/**
* Get the conference port identification associated with the call.
@ -4882,9 +4975,7 @@ PJ_DECL(pj_status_t) pjsua_codec_get_param( const pj_str_t *codec_id,
PJ_DECL(pj_status_t) pjsua_codec_set_param( const pj_str_t *codec_id,
const pjmedia_codec_param *param);
#if DISABLED_FOR_TICKET_1185
/**
* Create UDP media transports for all the calls. This function creates
* one UDP media transport for each call.
@ -4916,6 +5007,7 @@ PJ_DECL(pj_status_t)
pjsua_media_transports_attach( pjsua_media_transport tp[],
unsigned count,
pj_bool_t auto_delete);
#endif
/**

View File

@ -43,12 +43,65 @@ typedef enum pjsua_med_tp_st
} pjsua_med_tp_st;
/** Forward decl of pjsua call */
typedef struct pjsua_call pjsua_call;
/**
* Call's media stream.
*/
typedef struct pjsua_call_media
{
pjsua_call *call; /**< Parent call. */
pjmedia_type type; /**< Media type. */
unsigned idx; /**< This media index in parent call. */
pjsua_call_media_status state; /**< Media state. */
pjmedia_dir dir; /**< Media direction. */
/** The stream */
union {
/** Audio stream */
struct {
pjmedia_stream *stream; /**< The media session. */
int conf_slot; /**< Slot # in conference bridge. */
} a;
/** Video stream */
struct {
} v;
} strm;
pj_uint32_t ssrc; /**< RTP SSRC */
pj_uint32_t rtp_tx_ts; /**< Initial RTP timestamp for sender. */
pj_uint16_t rtp_tx_seq;/**< Initial RTP sequence for sender. */
pj_uint8_t rtp_tx_seq_ts_set;
/**< Bitmask flags if initial RTP sequence
and/or timestamp for sender are set.
bit 0/LSB : sequence flag
bit 1 : timestamp flag */
pjmedia_transport *tp; /**< Current media transport (can be 0) */
pj_status_t tp_ready; /**< Media transport status. */
pjmedia_transport *tp_orig; /**< Original media transport */
pj_bool_t tp_auto_del; /**< May delete media transport */
pjsua_med_tp_st tp_st; /**< Media transport state */
pj_sockaddr rtp_addr; /**< Current RTP source address
(used to update ICE default
address) */
pjmedia_srtp_use rem_srtp_use; /**< Remote's SRTP usage policy. */
} pjsua_call_media;
/**
* Maximum number of SDP "m=" lines to be supported.
*/
#define PJSUA_MAX_CALL_MEDIA PJMEDIA_MAX_SDP_MEDIA
/**
* Structure to be attached to invite dialog.
* Given a dialog "dlg", application can retrieve this structure
* by accessing dlg->mod_data[pjsua.mod.id].
*/
typedef struct pjsua_call
struct pjsua_call
{
unsigned index; /**< Index in pjsua array. */
pjsip_inv_session *inv; /**< The invite session. */
@ -63,31 +116,14 @@ typedef struct pjsua_call
int secure_level;/**< Signaling security level. */
pjsua_call_hold_type call_hold_type; /**< How to do call hold. */
pj_bool_t local_hold;/**< Flag for call-hold by local. */
pjsua_call_media_status media_st;/**< Media state. */
pjmedia_dir media_dir; /**< Media direction. */
pjmedia_session *session; /**< The media session. */
int audio_idx; /**< Index of m=audio in SDP. */
pj_uint32_t ssrc; /**< RTP SSRC */
pj_uint32_t rtp_tx_ts; /**< Initial RTP timestamp for sender. */
pj_uint16_t rtp_tx_seq;/**< Initial RTP sequence for sender. */
pj_uint8_t rtp_tx_seq_ts_set;
/**< Bitmask flags if initial RTP sequence
and/or timestamp for sender are set.
bit 0/LSB : sequence flag
bit 1 : timestamp flag */
int conf_slot; /**< Slot # in conference bridge. */
unsigned med_cnt; /**< Number of media in SDP. */
pjsua_call_media media[PJSUA_MAX_CALL_MEDIA]; /**< Array of media */
unsigned audio_idx; /**< Selected audio media. */
pjsip_evsub *xfer_sub; /**< Xfer server subscription, if this
call was triggered by xfer. */
pjmedia_transport *med_tp; /**< Current media transport. */
pj_status_t med_tp_ready;/**< Media transport status. */
pjmedia_transport *med_orig; /**< Original media transport */
pj_bool_t med_tp_auto_del; /**< May delete media transport */
pjsua_med_tp_st med_tp_st; /**< Media transport state */
pj_sockaddr med_rtp_addr; /**< Current RTP source address
(used to update ICE default
address) */
pj_stun_nat_type rem_nat_type; /**< NAT type of remote endpoint. */
pjmedia_srtp_use rem_srtp_use; /**< Remote's SRTP usage policy. */
char last_text_buf_[128]; /**< Buffer for last_text. */
@ -99,7 +135,7 @@ typedef struct pjsua_call
} lock_codec; /**< Data for codec locking when answer
contains multiple codecs. */
} pjsua_call;
};
/**
@ -270,6 +306,7 @@ struct pjsua_data
pj_caching_pool cp; /**< Global pool factory. */
pj_pool_t *pool; /**< pjsua's private pool. */
pj_mutex_t *mutex; /**< Mutex protection for this data */
pjsua_state state; /**< Library state. */
/* Logging: */
pjsua_logging_config log_cfg; /**< Current logging config. */
@ -402,6 +439,9 @@ PJ_INLINE(pjsua_im_data*) pjsua_im_data_dup(pj_pool_t *pool,
#define PJSUA_UNLOCK()
#endif
/* Core */
void pjsua_set_state(pjsua_state new_state);
/******
* STUN resolution
*/

View File

@ -118,7 +118,8 @@ PJ_DEF(void) pjsua_acc_config_dup( pj_pool_t *pool,
pjsip_auth_clt_pref_dup(pool, &dst->auth_pref, &src->auth_pref);
dst->ka_interval = src->ka_interval;
pjsua_transport_config_dup(pool, &dst->rtp_cfg, &src->rtp_cfg);
pj_strdup(pool, &dst->ka_data, &src->ka_data);
}

View File

@ -101,29 +101,19 @@ static void xfer_server_on_evsub_state( pjsip_evsub *sub, pjsip_event *event);
static void reset_call(pjsua_call_id id)
{
pjsua_call *call = &pjsua_var.calls[id];
unsigned i;
pj_bzero(call, sizeof(*call));
call->index = id;
call->inv = NULL;
call->user_data = NULL;
call->session = NULL;
call->audio_idx = -1;
call->ssrc = pj_rand();
call->rtp_tx_seq = 0;
call->rtp_tx_ts = 0;
call->rtp_tx_seq_ts_set = 0;
call->xfer_sub = NULL;
call->last_code = (pjsip_status_code) 0;
call->conf_slot = PJSUA_INVALID_ID;
call->last_text.ptr = call->last_text_buf_;
call->last_text.slen = 0;
call->conn_time.sec = 0;
call->conn_time.msec = 0;
call->res_time.sec = 0;
call->res_time.msec = 0;
call->rem_nat_type = PJ_STUN_NAT_TYPE_UNKNOWN;
call->rem_srtp_use = PJMEDIA_SRTP_DISABLED;
call->local_hold = PJ_FALSE;
pj_bzero(&call->lock_codec, sizeof(call->lock_codec));
for (i=0; i<PJ_ARRAY_SIZE(call->media); ++i) {
pjsua_call_media *call_med = &call->media[i];
call_med->ssrc = pj_rand();
call_med->strm.a.conf_slot = PJSUA_INVALID_ID;
call_med->call = call;
call_med->idx = i;
call_med->tp_auto_del = PJ_TRUE;
}
}
@ -823,7 +813,8 @@ pj_bool_t pjsua_call_on_incoming(pjsip_rx_data *rdata)
/* Init media channel */
status = pjsua_media_channel_init(call->index, PJSIP_ROLE_UAS,
call->secure_level,
rdata->tp_info.pool, offer,
rdata->tp_info.pool,
offer,
&sip_err_code);
if (status != PJ_SUCCESS) {
pjsua_perror(THIS_FILE, "Error initializing media channel", status);
@ -1118,12 +1109,14 @@ PJ_DEF(pj_bool_t) pjsua_call_is_active(pjsua_call_id call_id)
*/
PJ_DEF(pj_bool_t) pjsua_call_has_media(pjsua_call_id call_id)
{
pjsua_call *call = &pjsua_var.calls[call_id];
PJ_ASSERT_RETURN(call_id>=0 && call_id<(int)pjsua_var.ua_cfg.max_calls,
PJ_EINVAL);
return pjsua_var.calls[call_id].session != NULL;
return call->audio_idx >= 0 && call->media[call->audio_idx].strm.a.stream;
}
#if DISABLED_FOR_TICKET_1185
/*
* Retrieve the media session associated with this call.
*/
@ -1142,9 +1135,9 @@ PJ_DEF(pjmedia_transport*) pjsua_call_get_media_transport(pjsua_call_id cid)
{
PJ_ASSERT_RETURN(cid>=0 && cid<(int)pjsua_var.ua_cfg.max_calls,
NULL);
return pjsua_var.calls[cid].med_tp;
return pjsua_var.calls[cid].tp;
}
#endif /* Removed in 2.0 */
/* Acquire lock to the specified call_id */
pj_status_t acquire_call(const char *title,
@ -1238,7 +1231,7 @@ PJ_DEF(pjsua_conf_port_id) pjsua_call_get_conf_port(pjsua_call_id call_id)
if (status != PJ_SUCCESS)
return PJSUA_INVALID_ID;
port_id = call->conf_slot;
port_id = call->media[call->audio_idx].strm.a.conf_slot;
pjsip_dlg_dec_lock(dlg);
@ -1255,6 +1248,7 @@ PJ_DEF(pj_status_t) pjsua_call_get_info( pjsua_call_id call_id,
{
pjsua_call *call;
pjsip_dialog *dlg;
unsigned mi;
pj_status_t status;
PJ_ASSERT_RETURN(call_id>=0 && call_id<(int)pjsua_var.ua_cfg.max_calls,
@ -1329,13 +1323,28 @@ PJ_DEF(pj_status_t) pjsua_call_get_info( pjsua_call_id call_id,
sizeof(info->buf_.last_status_text));
}
/* media status and dir */
info->media_status = call->media_st;
info->media_dir = call->media_dir;
/* Build array of media status and dir */
info->audio_cnt = 0;
for (mi=0; mi < call->med_cnt &&
info->audio_cnt < PJ_ARRAY_SIZE(info->audio); ++mi)
{
pjsua_call_media *call_med = &call->media[mi];
if (call_med->type != PJMEDIA_TYPE_AUDIO)
continue;
info->audio[info->audio_cnt].index = mi;
info->audio[info->audio_cnt].media_status = call_med->state;
info->audio[info->audio_cnt].media_dir = call_med->dir;
info->audio[info->audio_cnt].conf_slot = call_med->strm.a.conf_slot;
++info->audio_cnt;
}
if (info->audio_cnt) {
info->media_status = info->audio[0].media_status;
info->media_dir = info->audio[0].media_dir;
}
/* conference slot number */
info->conf_slot = call->conf_slot;
info->conf_slot = call->media[call->audio_idx].strm.a.conf_slot;
/* calculate duration */
if (info->state >= PJSIP_INV_STATE_DISCONNECTED) {
@ -1959,13 +1968,14 @@ PJ_DEF(pj_status_t) pjsua_call_dial_dtmf( pjsua_call_id call_id,
if (status != PJ_SUCCESS)
return status;
if (!call->session) {
if (!pjsua_call_has_media(call_id)) {
PJ_LOG(3,(THIS_FILE, "Media is not established yet!"));
pjsip_dlg_dec_lock(dlg);
return PJ_EINVALIDOP;
}
status = pjmedia_session_dial_dtmf( call->session, 0, digits);
status = pjmedia_stream_dial_dtmf(
call->media[call->audio_idx].strm.a.stream, digits);
pjsip_dlg_dec_lock(dlg);
@ -2190,16 +2200,12 @@ static void dump_media_session(const char *indent,
unsigned i;
char *p = buf, *end = buf+maxlen;
int len;
pjmedia_session_info info;
pjmedia_session *session = call->session;
pjmedia_transport_info tp_info;
pjmedia_transport_info_init(&tp_info);
pjmedia_transport_get_info(call->med_tp, &tp_info);
pjmedia_session_get_info(session, &info);
for (i=0; i<info.stream_cnt; ++i) {
for (i=0; i<call->med_cnt; ++i) {
pjsua_call_media *call_med = &call->media[i];
pjmedia_stream_info info;
pjmedia_stream *stream = call_med->strm.a.stream;
pjmedia_transport_info tp_info;
pjmedia_rtcp_stat stat;
char rem_addr_buf[80];
const char *rem_addr;
@ -2208,7 +2214,42 @@ static void dump_media_session(const char *indent,
char packets[32], bytes[32], ipbytes[32], avg_bps[32], avg_ipbps[32];
pj_time_val media_duration, now;
pjmedia_session_get_stream_stat(session, i, &stat);
/* Check if the stream is deactivated */
if (call_med->tp == NULL || stream == NULL) {
const char *media_type_str;
switch (call_med->type) {
case PJMEDIA_TYPE_AUDIO:
media_type_str = "audio";
break;
case PJMEDIA_TYPE_VIDEO:
media_type_str = "video";
break;
case PJMEDIA_TYPE_APPLICATION:
media_type_str = "application";
break;
default:
media_type_str = "unknown";
break;
}
len = pj_ansi_snprintf(p, end-p,
"%s #%d m=%s deactivated\n",
indent, i, media_type_str);
if (len < 1 || len > end-p) {
*p = '\0';
return;
}
p += len;
continue;
}
pjmedia_transport_info_init(&tp_info);
pjmedia_transport_get_info(call_med->tp, &tp_info);
pjmedia_stream_get_info(stream, &info);
pjmedia_stream_get_stat(stream, &stat);
// rem_addr will contain actual address of RTP originator, instead of
// remote RTP address specified by stream which is fetched from the SDP.
// Please note that we are assuming only one stream per call.
@ -2222,27 +2263,27 @@ static void dump_media_session(const char *indent,
rem_addr = rem_addr_buf;
}
if (call->media_dir == PJMEDIA_DIR_NONE) {
if (call_med->dir == PJMEDIA_DIR_NONE) {
/* To handle when the stream that is currently being paused
* (http://trac.pjsip.org/repos/ticket/1079)
*/
dir = "inactive";
} else if (info.stream_info[i].dir == PJMEDIA_DIR_ENCODING)
} else if (info.dir == PJMEDIA_DIR_ENCODING)
dir = "sendonly";
else if (info.stream_info[i].dir == PJMEDIA_DIR_DECODING)
else if (info.dir == PJMEDIA_DIR_DECODING)
dir = "recvonly";
else if (info.stream_info[i].dir == PJMEDIA_DIR_ENCODING_DECODING)
else if (info.dir == PJMEDIA_DIR_ENCODING_DECODING)
dir = "sendrecv";
else
dir = "inactive";
len = pj_ansi_snprintf(buf, end-p,
len = pj_ansi_snprintf(p, end-p,
"%s #%d %.*s @%dKHz, %s, peer=%s",
indent, i,
(int)info.stream_info[i].fmt.encoding_name.slen,
info.stream_info[i].fmt.encoding_name.ptr,
info.stream_info[i].fmt.clock_rate / 1000,
(int)info.fmt.encoding_name.slen,
info.fmt.encoding_name.ptr,
info.fmt.clock_rate / 1000,
dir,
rem_addr);
if (len < 1 || len > end-p) {
@ -2293,7 +2334,7 @@ static void dump_media_session(const char *indent,
"%s IPDV : %7.3f %7.3f %7.3f %7.3f %7.3f"
#endif
"%s",
indent, info.stream_info[i].fmt.pt,
indent, info.fmt.pt,
last_update,
indent,
good_number(packets, stat.rx.pkt),
@ -2370,9 +2411,8 @@ static void dump_media_session(const char *indent,
"%s loss period: %7.3f %7.3f %7.3f %7.3f %7.3f\n"
"%s jitter : %7.3f %7.3f %7.3f %7.3f %7.3f%s",
indent,
info.stream_info[i].tx_pt,
info.stream_info[i].param->info.frm_ptime *
info.stream_info[i].param->setting.frm_per_pkt,
info.tx_pt,
info.param->info.frm_ptime * info.param->setting.frm_per_pkt,
last_update,
indent,
@ -2415,7 +2455,7 @@ static void dump_media_session(const char *indent,
*p = '\0';
len = pj_ansi_snprintf(p, end-p,
"%s RTT msec : %7.3f %7.3f %7.3f %7.3f %7.3f",
"%s RTT msec : %7.3f %7.3f %7.3f %7.3f %7.3f",
indent,
stat.rtt.min / 1000.0,
stat.rtt.mean / 1000.0,
@ -2470,7 +2510,7 @@ static void dump_media_session(const char *indent,
break;
}
clock_rate = info.stream_info[i].fmt.clock_rate;
clock_rate = info.fmt.clock_rate;
len = pj_ansi_snprintf(p, end-p, "\n%s Extended reports:", indent);
VALIDATE_PRINT_BUF();
@ -2943,8 +2983,9 @@ PJ_DEF(pj_status_t) pjsua_call_dump( pjsua_call_id call_id,
}
/* Get and ICE SRTP status */
#if DISABLED_FOR_TICKET_1185
pjmedia_transport_info_init(&tp_info);
pjmedia_transport_get_info(call->med_tp, &tp_info);
pjmedia_transport_get_info(call->tp, &tp_info);
if (tp_info.specific_info_cnt > 0) {
unsigned i;
for (i = 0; i < tp_info.specific_info_cnt; ++i) {
@ -2983,9 +3024,10 @@ PJ_DEF(pj_status_t) pjsua_call_dump( pjsua_call_id call_id,
}
}
}
#endif /* DISABLED_FOR_TICKET_1185 */
/* Dump session statistics */
if (with_media && call->session)
if (with_media && pjsua_call_has_media(call_id))
dump_media_session(indent, p, end-p, call);
pjsip_dlg_dec_lock(dlg);
@ -3063,6 +3105,7 @@ static pj_status_t perform_lock_codec(pjsua_call *call)
const pjmedia_sdp_session *local_sdp = NULL, *new_sdp;
const pjmedia_sdp_media *ref_m;
pjmedia_sdp_media *m;
pjsua_call_media *call_med = &call->media[call->audio_idx];
unsigned i, codec_cnt = 0;
pj_bool_t rem_can_update;
pjsip_tx_data *tdata;
@ -3097,9 +3140,9 @@ static pj_status_t perform_lock_codec(pjsua_call *call)
return PJMEDIA_SDP_EINVER;
/* Verify if media is deactivated */
if (call->media_st == PJSUA_CALL_MEDIA_NONE ||
call->media_st == PJSUA_CALL_MEDIA_ERROR ||
call->media_dir == PJMEDIA_DIR_NONE)
if (call_med->state == PJSUA_CALL_MEDIA_NONE ||
call_med->state == PJSUA_CALL_MEDIA_ERROR ||
call_med->dir == PJMEDIA_DIR_NONE)
{
return PJ_EINVALIDOP;
}
@ -3189,6 +3232,7 @@ static pj_status_t lock_codec(pjsua_call *call)
const pjmedia_sdp_session *local_sdp, *remote_sdp;
const pjmedia_sdp_media *rem_m, *loc_m;
unsigned codec_cnt=0, i;
pjsua_call_media *call_med = &call->media[call->audio_idx];
pj_time_val delay = {0, 0};
const pj_str_t st_update = {"UPDATE", 6};
pj_status_t status;
@ -3206,9 +3250,9 @@ static pj_status_t lock_codec(pjsua_call *call)
}
/* Skip this if the media is inactive or error */
if (call->media_st == PJSUA_CALL_MEDIA_NONE ||
call->media_st == PJSUA_CALL_MEDIA_ERROR ||
call->media_dir == PJMEDIA_DIR_NONE)
if (call_med->state == PJSUA_CALL_MEDIA_NONE ||
call_med->state == PJSUA_CALL_MEDIA_ERROR ||
call_med->dir == PJMEDIA_DIR_NONE)
{
return PJ_SUCCESS;
}
@ -3524,7 +3568,8 @@ static void call_disconnect( pjsip_inv_session *inv,
return;
/* Add SDP in 488 status */
if (call && call->med_tp && tdata->msg->type==PJSIP_RESPONSE_MSG &&
#if DISABLED_FOR_TICKET_1185
if (call && call->tp && tdata->msg->type==PJSIP_RESPONSE_MSG &&
code==PJSIP_SC_NOT_ACCEPTABLE_HERE)
{
pjmedia_sdp_session *local_sdp;
@ -3539,6 +3584,7 @@ static void call_disconnect( pjsip_inv_session *inv,
&tdata->msg->body);
}
}
#endif
pjsip_inv_send_msg(inv, tdata);
}
@ -3654,7 +3700,7 @@ static pj_status_t modify_sdp_of_call_hold(pjsua_call *call,
* (See RFC 3264 Section 8.4 and RFC 4317 Section 3.1)
*/
/* http://trac.pjsip.org/repos/ticket/880
if (call->media_dir != PJMEDIA_DIR_ENCODING) {
if (call->dir != PJMEDIA_DIR_ENCODING) {
*/
/* https://trac.pjsip.org/repos/ticket/1142:
* configuration to use c=0.0.0.0 for call hold.
@ -3694,7 +3740,7 @@ static pj_status_t modify_sdp_of_call_hold(pjsua_call *call,
pjmedia_sdp_media_remove_all_attr(m, "recvonly");
pjmedia_sdp_media_remove_all_attr(m, "inactive");
if (call->media_dir & PJMEDIA_DIR_ENCODING) {
if (call->media[call->audio_idx].dir & PJMEDIA_DIR_ENCODING) {
/* Add sendonly attribute */
attr = pjmedia_sdp_attr_create(pool, "sendonly", NULL);
pjmedia_sdp_media_add_attr(m, attr);

View File

@ -103,10 +103,8 @@ PJ_DEF(void) pjsua_config_default(pjsua_config *cfg)
cfg->stun_ignore_failure = PJ_TRUE;
cfg->force_lr = PJ_TRUE;
cfg->enable_unsolicited_mwi = PJ_TRUE;
#if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0)
cfg->use_srtp = PJSUA_DEFAULT_USE_SRTP;
cfg->srtp_secure_signaling = PJSUA_DEFAULT_SRTP_SECURE_SIGNALING;
#endif
cfg->hangup_forked_call = PJ_TRUE;
cfg->use_timer = PJSUA_SIP_TIMER_OPTIONAL;
@ -176,11 +174,11 @@ PJ_DEF(void) pjsua_acc_config_default(pjsua_acc_config *cfg)
cfg->timer_setting = pjsua_var.ua_cfg.timer_setting;
cfg->ka_interval = 15;
cfg->ka_data = pj_str("\r\n");
#if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0)
cfg->max_audio_cnt = 1;
pjsua_transport_config_default(&cfg->rtp_cfg);
cfg->use_srtp = pjsua_var.ua_cfg.use_srtp;
cfg->srtp_secure_signaling = pjsua_var.ua_cfg.srtp_secure_signaling;
cfg->srtp_optional_dup_offer = pjsua_var.ua_cfg.srtp_optional_dup_offer;
#endif
cfg->reg_retry_interval = PJSUA_REG_RETRY_INTERVAL;
cfg->contact_rewrite_method = PJSUA_CONTACT_REWRITE_METHOD;
cfg->use_rfc5626 = PJ_TRUE;
@ -223,7 +221,6 @@ PJ_DEF(void) pjsua_media_config_default(pjsua_media_config *cfg)
cfg->turn_conn_type = PJ_TURN_TP_UDP;
}
/*****************************************************************************
* This is a very simple PJSIP module, whose sole purpose is to display
* incoming and outgoing messages to log. This module will have priority
@ -378,6 +375,7 @@ static pj_bool_t options_on_rx_request(pjsip_rx_data *rdata)
}
/* Get media socket info, make sure transport is ready */
#if DISABLED_FOR_TICKET_1185
if (pjsua_var.calls[0].med_tp) {
pjmedia_transport_info_init(&tpinfo);
pjmedia_transport_get_info(pjsua_var.calls[0].med_tp, &tpinfo);
@ -389,8 +387,9 @@ static pj_bool_t options_on_rx_request(pjsip_rx_data *rdata)
pjsip_create_sdp_body(tdata->pool, sdp, &tdata->msg->body);
}
}
#endif
/* Send response statelessly */
/* Send response */
pjsip_get_response_addr(tdata->pool, rdata, &res_addr);
status = pjsip_endpt_send_response(pjsua_var.endpt, &res_addr, tdata, NULL, NULL);
if (status != PJ_SUCCESS)
@ -659,6 +658,7 @@ PJ_DEF(pj_status_t) pjsua_create(void)
&pjsua_var.endpt);
PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);
pjsua_set_state(PJSUA_STATE_CREATED);
return PJ_SUCCESS;
}
@ -918,6 +918,8 @@ PJ_DEF(pj_status_t) pjsua_init( const pjsua_config *ua_cfg,
PJ_LOG(3,(THIS_FILE, "pjsua version %s for %s initialized",
pj_get_version(), PJ_OS_NAME));
pjsua_set_state(PJSUA_STATE_INIT);
return PJ_SUCCESS;
on_error:
@ -1275,6 +1277,12 @@ PJ_DEF(pj_status_t) pjsua_destroy(void)
{
int i; /* Must be signed */
if (pjsua_var.state > PJSUA_STATE_NULL &&
pjsua_var.state < PJSUA_STATE_CLOSING)
{
pjsua_set_state(PJSUA_STATE_CLOSING);
}
/* Signal threads to quit: */
pjsua_var.thread_quit_flag = 1;
@ -1452,10 +1460,34 @@ PJ_DEF(pj_status_t) pjsua_destroy(void)
/* Clear pjsua_var */
pj_bzero(&pjsua_var, sizeof(pjsua_var));
pjsua_set_state(PJSUA_STATE_NULL);
/* Done. */
return PJ_SUCCESS;
}
void pjsua_set_state(pjsua_state new_state)
{
const char *state_name[] = {
"NULL",
"CREATED",
"INIT",
"STARTING",
"RUNNING",
"CLOSING"
};
pjsua_state old_state = pjsua_var.state;
pjsua_var.state = new_state;
PJ_LOG(4,(THIS_FILE, "PJSUA state changed: %s --> %s",
state_name[old_state], state_name[new_state]));
}
/* Get state */
PJ_DEF(pjsua_state) pjsua_get_state(void)
{
return pjsua_var.state;
}
/**
* Application is recommended to call this function after all initialization
@ -1468,6 +1500,8 @@ PJ_DEF(pj_status_t) pjsua_start(void)
{
pj_status_t status;
pjsua_set_state(PJSUA_STATE_STARTING);
status = pjsua_call_subsys_start();
if (status != PJ_SUCCESS)
return status;
@ -1480,6 +1514,8 @@ PJ_DEF(pj_status_t) pjsua_start(void)
if (status != PJ_SUCCESS)
return status;
pjsua_set_state(PJSUA_STATE_RUNNING);
return PJ_SUCCESS;
}
@ -2563,6 +2599,7 @@ PJ_DEF(void) pjsua_dump(pj_bool_t detail)
pjmedia_endpt_dump(pjsua_get_pjmedia_endpt());
PJ_LOG(3,(THIS_FILE, "Dumping media transports:"));
#if DISABLED_FOR_TICKET_1185
for (i=0; i<pjsua_var.ua_cfg.max_calls; ++i) {
pjsua_call *call = &pjsua_var.calls[i];
pjmedia_transport_info tpinfo;
@ -2579,6 +2616,7 @@ PJ_DEF(void) pjsua_dump(pj_bool_t detail)
pj_sockaddr_print(&tpinfo.sock_info.rtp_addr_name, addr_buf,
sizeof(addr_buf), 3)));
}
#endif
pjsip_tsx_layer_dump(detail);
pjsip_ua_dump(detail);

File diff suppressed because it is too large Load Diff