Re #1263:
- Renamed API pjsua_call_set_vid_out() with pjsua_call_set_vid_strm(). - Implemented initial version of the function, features covered: - add, remove video media stream during the call - change which device to use during the call - start/stop video stream transmission git-svn-id: https://svn.pjsip.org/repos/pjproject/branches/projects/2.0-dev@3634 74dad513-b988-da41-8d7b-12977e46ad98
This commit is contained in:
parent
06dffff4a7
commit
b4d4dade23
|
@ -1451,7 +1451,7 @@ static pj_status_t parse_args(int argc, char *argv[],
|
|||
++cur_acc->max_video_cnt;
|
||||
cur_acc->vid_in_auto_show = PJ_TRUE;
|
||||
cur_acc->vid_out_auto_transmit = PJ_TRUE;
|
||||
PJ_TODO(implement_pjsua_option_for_vid_auto_show_transmit);
|
||||
PJ_TODO(implement_pjsua_option_for_vid_auto_show_and_transmit);
|
||||
break;
|
||||
case OPT_EXTRA_AUDIO:
|
||||
++cur_acc->max_audio_cnt;
|
||||
|
@ -3315,6 +3315,8 @@ static void vid_show_help(void)
|
|||
puts("| vid help Show this help screen |");
|
||||
puts("| vid call rx on|off Enable/disable incoming video for current call |");
|
||||
puts("| vid call tx on|off Enable/disable video tx for current call |");
|
||||
puts("| vid call add Add video stream for current call |");
|
||||
puts("| vid call remove [idx] Remove video stream #idx for current call |");
|
||||
puts("| vid dev list List all video devices |");
|
||||
puts("| vid dev refresh Refresh video device list |");
|
||||
puts("| vid dev prev on|off ID Enable/disable preview for specified device ID |");
|
||||
|
@ -3753,9 +3755,19 @@ static void vid_handle_menu(char *menuin)
|
|||
if (strcmp(argv[1], "help")==0 || argc == 1) {
|
||||
vid_show_help();
|
||||
} else if (strcmp(argv[1], "call")==0) {
|
||||
pjsua_call_vid_strm_op_param param;
|
||||
pj_bool_t tx = (strcmp(argv[2], "tx") == 0);
|
||||
pj_bool_t on = (strcmp(argv[3], "on") == 0);
|
||||
if (tx) {
|
||||
pj_bool_t on = (strcmp(argv[3], "on") == 0);
|
||||
}
|
||||
|
||||
if (strcmp(argv[2], "add")==0) {
|
||||
pjsua_call_set_vid_strm(current_call, PJSUA_CALL_VID_STRM_ADD, NULL);
|
||||
}
|
||||
if (strcmp(argv[2], "remove")==0) {
|
||||
param.med_idx = argc >= 4? atoi(argv[3]) : -1;
|
||||
pjsua_call_set_vid_strm(current_call, PJSUA_CALL_VID_STRM_REMOVE, ¶m);
|
||||
}
|
||||
PJ_TODO(vid_enable_disable_video_on_call);
|
||||
PJ_LOG(1,(THIS_FILE, "Not implemented"));
|
||||
} else if (strcmp(argv[1], "dev")==0) {
|
||||
|
|
|
@ -369,6 +369,69 @@ typedef enum pjsua_state
|
|||
} pjsua_state;
|
||||
|
||||
|
||||
/**
|
||||
* This enumeration represents video stream operation on a call.
|
||||
* See also #pjsua_call_vid_strm_op_param for further info.
|
||||
*/
|
||||
typedef enum pjsua_call_vid_strm_op
|
||||
{
|
||||
/**
|
||||
* Add a new video stream.
|
||||
*/
|
||||
PJSUA_CALL_VID_STRM_ADD,
|
||||
|
||||
/**
|
||||
* Remove an existing video stream.
|
||||
*/
|
||||
PJSUA_CALL_VID_STRM_REMOVE,
|
||||
|
||||
/**
|
||||
* Modify an existing video stream, such as changing the capture device.
|
||||
*/
|
||||
PJSUA_CALL_VID_STRM_MODIFY,
|
||||
|
||||
/**
|
||||
* Start transmitting video stream.
|
||||
*/
|
||||
PJSUA_CALL_VID_STRM_START_TRANSMIT,
|
||||
|
||||
/**
|
||||
* Stop transmitting video stream.
|
||||
*/
|
||||
PJSUA_CALL_VID_STRM_STOP_TRANSMIT,
|
||||
|
||||
} pjsua_call_vid_strm_op;
|
||||
|
||||
|
||||
/**
|
||||
* Parameters for video stream operation on a call.
|
||||
*/
|
||||
typedef struct pjsua_call_vid_strm_op_param
|
||||
{
|
||||
/**
|
||||
* Specify the media stream index. This can be set to -1 to denote
|
||||
* the default video stream in the call, which is the first active
|
||||
* video stream or any first video stream if none is active.
|
||||
*
|
||||
* This field is valid for all video stream operations, except
|
||||
* PJSUA_CALL_VID_STRM_ADD.
|
||||
*/
|
||||
int med_idx;
|
||||
|
||||
/**
|
||||
* Specify the video capture device ID. This can be set to
|
||||
* PJMEDIA_VID_DEFAULT_CAPTURE_DEV to specify the default capture
|
||||
* device as configured in the account.
|
||||
*
|
||||
* This field is valid for the following video stream operations:
|
||||
* PJSUA_CALL_VID_STRM_ADD, PJSUA_CALL_VID_STRM_MODIFY, and
|
||||
* PJSUA_CALL_VID_STRM_START_TRANSMIT.
|
||||
*/
|
||||
pjmedia_vid_dev_index cap_dev;
|
||||
|
||||
} pjsua_call_vid_strm_op_param;
|
||||
|
||||
|
||||
/**
|
||||
* Logging configuration, which can be (optionally) specified when calling
|
||||
* #pjsua_init(). Application must call #pjsua_logging_config_default() to
|
||||
|
@ -3680,43 +3743,24 @@ PJ_DECL(pj_status_t) pjsua_call_dump(pjsua_call_id call_id,
|
|||
*/
|
||||
PJ_DECL(int) pjsua_call_get_vid_stream_idx(pjsua_call_id call_id);
|
||||
|
||||
|
||||
/**
|
||||
* Start, stop, and/or manipulate video transmission for the specified
|
||||
* call. This would trigger a re-INVITE or UPDATE to be sent for the
|
||||
* call. This function may add, remove, or modify existing video media
|
||||
* stream, depending on the media index specified (the \a med_idx argument).
|
||||
*
|
||||
* To add a new or edit existing video stream (for transmission), specify
|
||||
* a valid video capture device ID or PJMEDIA_VID_DEFAULT_CAPTURE_DEV in
|
||||
* the \a cap_dev argument. If \a med_idx is set to default stream (-1),
|
||||
* then the function will modify existing video stream if one exists, or
|
||||
* add a new one if it doesn't. If \a med_idx is set to a specific stream
|
||||
* index, the function will modify that video stream. Otherwise if \a med_idx
|
||||
* is set to value larger than the current media count, a new video stream
|
||||
* will be added to the call.
|
||||
*
|
||||
* To remove an existing video stream, specify PJMEDIA_VID_INVALID_DEV in
|
||||
* \a cap_dev argument. If \a med_idx is set to default stream (-1), this
|
||||
* will remove the default/first video stream in the call, otherwise
|
||||
* application can put a specific value to request removal of that particular
|
||||
* video stream.
|
||||
* Add, remove, modify, and/or manipulate video media stream for the
|
||||
* specified call. This may trigger a re-INVITE or UPDATE to be sent
|
||||
* for the call.
|
||||
*
|
||||
* @param call_id Call identification.
|
||||
* @param med_idx The media stream index. Currently the value MUST
|
||||
* be -1 to denote the default video stream in the
|
||||
* call.
|
||||
* @param cap_dev To add or modify existing video media stream,
|
||||
* specify PJMEDIA_VID_DEFAULT_CAPTURE_DEV to use
|
||||
* the default capture device as configured in the
|
||||
* account, or specify a specific capture device ID.
|
||||
* To disable an existing video stream, specify
|
||||
* PJMEDIA_VID_INVALID_DEV for this parameter.
|
||||
* @param op The video stream operation to be performed,
|
||||
* possible values are #pjsua_call_vid_strm_op.
|
||||
* @param param The parameters for the video stream operation.
|
||||
*
|
||||
* @return PJ_SUCCESS on success or the appropriate error.
|
||||
*/
|
||||
PJ_DECL(pj_status_t) pjsua_call_set_vid_out(pjsua_call_id call_id,
|
||||
int med_idx,
|
||||
pjmedia_vid_dev_index cap_dev);
|
||||
PJ_DECL(pj_status_t) pjsua_call_set_vid_strm (
|
||||
pjsua_call_id call_id,
|
||||
pjsua_call_vid_strm_op op,
|
||||
const pjsua_call_vid_strm_op_param *param);
|
||||
|
||||
|
||||
/**
|
||||
* Get media stream info for the specified media index.
|
||||
|
|
|
@ -74,6 +74,8 @@ typedef struct pjsua_call_media
|
|||
pjmedia_vid_stream *stream; /**< The video stream. */
|
||||
pjsua_vid_win_id cap_win_id;/**< The video capture window */
|
||||
pjsua_vid_win_id rdr_win_id;/**< The video render window */
|
||||
pjmedia_vid_dev_index cap_dev; /**< The video capture device */
|
||||
pjmedia_vid_dev_index rdr_dev; /**< The video-in render device */
|
||||
} v;
|
||||
|
||||
} strm;
|
||||
|
|
|
@ -1313,11 +1313,11 @@ static void sort_media(const pjmedia_sdp_session *sdp,
|
|||
}
|
||||
|
||||
/* Initialize the media line */
|
||||
static pj_status_t pjsua_call_media_init(pjsua_call_media *call_med,
|
||||
pjmedia_type type,
|
||||
const pjsua_transport_config *tcfg,
|
||||
int security_level,
|
||||
int *sip_err_code)
|
||||
pj_status_t pjsua_call_media_init(pjsua_call_media *call_med,
|
||||
pjmedia_type type,
|
||||
const pjsua_transport_config *tcfg,
|
||||
int security_level,
|
||||
int *sip_err_code)
|
||||
{
|
||||
pjsua_acc *acc = &pjsua_var.acc[call_med->call->acc_id];
|
||||
pj_status_t status;
|
||||
|
@ -1342,6 +1342,22 @@ static pj_status_t pjsua_call_media_init(pjsua_call_media *call_med,
|
|||
}
|
||||
|
||||
call_med->tp_st = PJSUA_MED_TP_IDLE;
|
||||
|
||||
/* While in initial call, set default video devices */
|
||||
if (type == PJMEDIA_TYPE_VIDEO) {
|
||||
call_med->strm.v.rdr_dev = acc->cfg.vid_rend_dev;
|
||||
call_med->strm.v.cap_dev = acc->cfg.vid_cap_dev;
|
||||
if (call_med->strm.v.rdr_dev == PJMEDIA_VID_DEFAULT_RENDER_DEV) {
|
||||
pjmedia_vid_dev_info info;
|
||||
pjmedia_vid_dev_get_info(call_med->strm.v.rdr_dev, &info);
|
||||
call_med->strm.v.rdr_dev = info.id;
|
||||
}
|
||||
if (call_med->strm.v.cap_dev == PJMEDIA_VID_DEFAULT_CAPTURE_DEV) {
|
||||
pjmedia_vid_dev_info info;
|
||||
pjmedia_vid_dev_get_info(call_med->strm.v.cap_dev, &info);
|
||||
call_med->strm.v.cap_dev = info.id;
|
||||
}
|
||||
}
|
||||
} else if (call_med->tp_st == PJSUA_MED_TP_DISABLED) {
|
||||
/* Media is being reenabled. */
|
||||
call_med->tp_st = PJSUA_MED_TP_INIT;
|
||||
|
|
|
@ -607,7 +607,8 @@ pj_status_t video_channel_update(pjsua_call_media *call_med,
|
|||
return status;
|
||||
|
||||
/* Setup decoding direction */
|
||||
if (si->dir & PJMEDIA_DIR_DECODING) {
|
||||
if (si->dir & PJMEDIA_DIR_DECODING)
|
||||
{
|
||||
pjsua_vid_win_id wid;
|
||||
pjsua_vid_win *w;
|
||||
|
||||
|
@ -620,7 +621,8 @@ pj_status_t video_channel_update(pjsua_call_media *call_med,
|
|||
/* Create stream video window */
|
||||
status = create_vid_win(PJSUA_WND_TYPE_STREAM,
|
||||
&media_port->info.fmt,
|
||||
acc->cfg.vid_rend_dev,
|
||||
call_med->strm.v.rdr_dev,
|
||||
//acc->cfg.vid_rend_dev,
|
||||
PJSUA_INVALID_ID,
|
||||
acc->cfg.vid_in_auto_show,
|
||||
&wid);
|
||||
|
@ -646,8 +648,7 @@ pj_status_t video_channel_update(pjsua_call_media *call_med,
|
|||
}
|
||||
|
||||
/* Setup encoding direction */
|
||||
if (si->dir & PJMEDIA_DIR_ENCODING && !call->local_hold &&
|
||||
acc->cfg.vid_out_auto_transmit)
|
||||
if (si->dir & PJMEDIA_DIR_ENCODING && !call->local_hold)
|
||||
{
|
||||
pjsua_vid_win *w;
|
||||
pjsua_vid_win_id wid;
|
||||
|
@ -661,8 +662,10 @@ pj_status_t video_channel_update(pjsua_call_media *call_med,
|
|||
/* Create preview video window */
|
||||
status = create_vid_win(PJSUA_WND_TYPE_PREVIEW,
|
||||
&media_port->info.fmt,
|
||||
acc->cfg.vid_rend_dev,
|
||||
acc->cfg.vid_cap_dev,
|
||||
call_med->strm.v.rdr_dev,
|
||||
call_med->strm.v.cap_dev,
|
||||
//acc->cfg.vid_rend_dev,
|
||||
//acc->cfg.vid_cap_dev,
|
||||
PJ_FALSE,
|
||||
&wid);
|
||||
if (status != PJ_SUCCESS)
|
||||
|
@ -736,6 +739,13 @@ pj_status_t video_channel_update(pjsua_call_media *call_med,
|
|||
PJ_LOG(4,(THIS_FILE,"Media updates%s", info));
|
||||
}
|
||||
|
||||
if (acc->cfg.vid_out_auto_transmit) {
|
||||
status = pjmedia_vid_stream_pause(call_med->strm.v.stream,
|
||||
PJMEDIA_DIR_ENCODING);
|
||||
if (status != PJ_SUCCESS)
|
||||
return status;
|
||||
}
|
||||
|
||||
return PJ_SUCCESS;
|
||||
}
|
||||
|
||||
|
@ -1006,6 +1016,501 @@ PJ_DEF(pj_status_t) pjsua_vid_win_set_size( pjsua_vid_win_id wid,
|
|||
}
|
||||
|
||||
|
||||
static void call_get_vid_strm_info(pjsua_call *call,
|
||||
int *first_active,
|
||||
int *first_inactive,
|
||||
unsigned *active_cnt,
|
||||
unsigned *cnt)
|
||||
{
|
||||
unsigned i, var_cnt = 0;
|
||||
|
||||
if (first_active && ++var_cnt)
|
||||
*first_active = -1;
|
||||
if (first_inactive && ++var_cnt)
|
||||
*first_inactive = -1;
|
||||
if (active_cnt && ++var_cnt)
|
||||
*active_cnt = 0;
|
||||
if (cnt && ++var_cnt)
|
||||
*cnt = 0;
|
||||
|
||||
for (i = 0; i < call->med_cnt && var_cnt; ++i) {
|
||||
if (call->media[i].type == PJMEDIA_TYPE_VIDEO) {
|
||||
if (call->media[i].dir != PJMEDIA_DIR_NONE)
|
||||
{
|
||||
if (first_active && *first_active == -1) {
|
||||
*first_active = i;
|
||||
--var_cnt;
|
||||
}
|
||||
if (active_cnt)
|
||||
++(*active_cnt);
|
||||
} else if (first_inactive && *first_inactive == -1) {
|
||||
*first_inactive = i;
|
||||
--var_cnt;
|
||||
}
|
||||
if (cnt)
|
||||
++(*cnt);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Send SDP reoffer. */
|
||||
static pj_status_t call_reoffer_sdp(pjsua_call_id call_id,
|
||||
const pjmedia_sdp_session *sdp)
|
||||
{
|
||||
pjsua_call *call;
|
||||
pjsip_tx_data *tdata;
|
||||
pjsip_dialog *dlg;
|
||||
pj_status_t status;
|
||||
|
||||
status = acquire_call("call_reoffer_sdp()", call_id, &call, &dlg);
|
||||
if (status != PJ_SUCCESS)
|
||||
return status;
|
||||
|
||||
if (call->inv->state != PJSIP_INV_STATE_CONFIRMED) {
|
||||
PJ_LOG(3,(THIS_FILE, "Can not re-INVITE call that is not confirmed"));
|
||||
pjsip_dlg_dec_lock(dlg);
|
||||
return PJSIP_ESESSIONSTATE;
|
||||
}
|
||||
|
||||
/* Create re-INVITE with new offer */
|
||||
status = pjsip_inv_reinvite( call->inv, NULL, sdp, &tdata);
|
||||
if (status != PJ_SUCCESS) {
|
||||
pjsua_perror(THIS_FILE, "Unable to create re-INVITE", status);
|
||||
pjsip_dlg_dec_lock(dlg);
|
||||
return status;
|
||||
}
|
||||
|
||||
/* Send the request */
|
||||
status = pjsip_inv_send_msg( call->inv, tdata);
|
||||
if (status != PJ_SUCCESS) {
|
||||
pjsua_perror(THIS_FILE, "Unable to send re-INVITE", status);
|
||||
pjsip_dlg_dec_lock(dlg);
|
||||
return status;
|
||||
}
|
||||
|
||||
pjsip_dlg_dec_lock(dlg);
|
||||
|
||||
return PJ_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
pj_status_t pjsua_call_media_init(pjsua_call_media *call_med,
|
||||
pjmedia_type type,
|
||||
const pjsua_transport_config *tcfg,
|
||||
int security_level,
|
||||
int *sip_err_code);
|
||||
|
||||
|
||||
/* Add a new video stream into a call */
|
||||
static pj_status_t call_add_video(pjsua_call *call,
|
||||
pjmedia_vid_dev_index cap_dev)
|
||||
{
|
||||
pj_pool_t *pool = call->inv->pool_prov;
|
||||
pjsua_acc_config *acc_cfg = &pjsua_var.acc[call->acc_id].cfg;
|
||||
pjsua_call_media *call_med;
|
||||
pjmedia_sdp_session *sdp;
|
||||
pjmedia_sdp_media *sdp_m;
|
||||
pjmedia_transport_info tpinfo;
|
||||
pjmedia_vid_dev_info vinfo;
|
||||
unsigned active_cnt;
|
||||
pj_status_t status;
|
||||
|
||||
/* Verify media slot availability */
|
||||
if (call->med_cnt == PJSUA_MAX_CALL_MEDIA)
|
||||
return PJ_ETOOMANY;
|
||||
|
||||
call_get_vid_strm_info(call, NULL, NULL, &active_cnt, NULL);
|
||||
if (active_cnt == acc_cfg->max_video_cnt)
|
||||
return PJ_ETOOMANY;
|
||||
|
||||
/* Verify the capture device */
|
||||
status = pjmedia_vid_dev_get_info(cap_dev, &vinfo);
|
||||
if (status != PJ_SUCCESS)
|
||||
return status;
|
||||
|
||||
if (vinfo.dir != PJMEDIA_DIR_CAPTURE)
|
||||
return PJ_EINVAL;
|
||||
|
||||
cap_dev = vinfo.id;
|
||||
|
||||
/* Get active local SDP */
|
||||
status = pjmedia_sdp_neg_get_active_local(call->inv->neg, &sdp);
|
||||
if (status != PJ_SUCCESS)
|
||||
return status;
|
||||
|
||||
/* Initialize call media */
|
||||
call_med = &call->media[call->med_cnt++];
|
||||
|
||||
status = pjsua_call_media_init(call_med, PJMEDIA_TYPE_VIDEO,
|
||||
&acc_cfg->rtp_cfg, call->secure_level,
|
||||
NULL);
|
||||
if (status != PJ_SUCCESS)
|
||||
goto on_error;
|
||||
|
||||
/* Override default capture device setting */
|
||||
call_med->strm.v.cap_dev = cap_dev;
|
||||
|
||||
/* Init transport media */
|
||||
status = pjmedia_transport_media_create(call_med->tp, pool, 0,
|
||||
NULL, call_med->idx);
|
||||
if (status != PJ_SUCCESS)
|
||||
goto on_error;
|
||||
|
||||
call_med->tp_st = PJSUA_MED_TP_INIT;
|
||||
|
||||
/* Get transport address info */
|
||||
pjmedia_transport_info_init(&tpinfo);
|
||||
pjmedia_transport_get_info(call_med->tp, &tpinfo);
|
||||
|
||||
/* Create SDP media line */
|
||||
status = pjmedia_endpt_create_video_sdp(pjsua_var.med_endpt, pool,
|
||||
&tpinfo.sock_info, 0, &sdp_m);
|
||||
if (status != PJ_SUCCESS)
|
||||
goto on_error;
|
||||
|
||||
sdp->media[sdp->media_count++] = sdp_m;
|
||||
|
||||
/* Update SDP media line by media transport */
|
||||
status = pjmedia_transport_encode_sdp(call_med->tp, pool,
|
||||
sdp, NULL, call_med->idx);
|
||||
if (status != PJ_SUCCESS)
|
||||
goto on_error;
|
||||
|
||||
status = call_reoffer_sdp(call->index, sdp);
|
||||
if (status != PJ_SUCCESS)
|
||||
goto on_error;
|
||||
|
||||
return PJ_SUCCESS;
|
||||
|
||||
on_error:
|
||||
if (call_med->tp) {
|
||||
pjmedia_transport_close(call_med->tp);
|
||||
call_med->tp = call_med->tp_orig = NULL;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
/* Remove a video stream from a call */
|
||||
static pj_status_t call_remove_video(pjsua_call *call,
|
||||
int med_idx)
|
||||
{
|
||||
pjsua_call_media *call_med;
|
||||
pjmedia_sdp_session *sdp;
|
||||
pj_status_t status;
|
||||
|
||||
/* Verify and normalize media index */
|
||||
if (med_idx == -1) {
|
||||
int first_active;
|
||||
|
||||
call_get_vid_strm_info(call, &first_active, NULL, NULL, NULL);
|
||||
if (first_active == -1)
|
||||
return PJ_ENOTFOUND;
|
||||
|
||||
med_idx = first_active;
|
||||
}
|
||||
|
||||
call_med = &call->media[med_idx];
|
||||
|
||||
/* Verify if the stream media type is video */
|
||||
if (call_med->type != PJMEDIA_TYPE_VIDEO)
|
||||
return PJ_EINVAL;
|
||||
|
||||
/* Verify if the stream already disabled */
|
||||
if (call_med->dir != PJMEDIA_DIR_NONE)
|
||||
return PJ_SUCCESS;
|
||||
|
||||
/* Mark media transport to disabled */
|
||||
// Don't close this here, as SDP negotiation has not been
|
||||
// done and stream may be still active.
|
||||
call_med->tp_st = PJSUA_MED_TP_DISABLED;
|
||||
|
||||
/* Get active local SDP */
|
||||
status = pjmedia_sdp_neg_get_active_local(call->inv->neg, &sdp);
|
||||
if (status != PJ_SUCCESS)
|
||||
return status;
|
||||
|
||||
pj_assert(med_idx < (int)sdp->media_count);
|
||||
sdp->media[med_idx]->desc.port = 0;
|
||||
|
||||
status = call_reoffer_sdp(call->index, sdp);
|
||||
if (status != PJ_SUCCESS)
|
||||
return status;
|
||||
|
||||
return PJ_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/* Modify a video stream in a call */
|
||||
static pj_status_t call_modify_video(pjsua_call *call,
|
||||
int med_idx,
|
||||
pjmedia_vid_dev_index cap_dev)
|
||||
{
|
||||
pjsua_call_media *call_med;
|
||||
pjmedia_vid_dev_info info;
|
||||
pjsua_vid_win *w, *new_w = NULL;
|
||||
pjsua_vid_win_id wid, new_wid;
|
||||
pjmedia_port *media_port;
|
||||
pj_status_t status;
|
||||
|
||||
/* Verify and normalize media index */
|
||||
if (med_idx == -1) {
|
||||
int first_active;
|
||||
|
||||
call_get_vid_strm_info(call, &first_active, NULL, NULL, NULL);
|
||||
if (first_active == -1)
|
||||
return PJ_ENOTFOUND;
|
||||
|
||||
med_idx = first_active;
|
||||
}
|
||||
|
||||
call_med = &call->media[med_idx];
|
||||
|
||||
/* Verify if the stream media type is video */
|
||||
if (call_med->type != PJMEDIA_TYPE_VIDEO)
|
||||
return PJ_EINVAL;
|
||||
|
||||
/* Verify the capture device */
|
||||
status = pjmedia_vid_dev_get_info(cap_dev, &info);
|
||||
if (status != PJ_SUCCESS)
|
||||
return status;
|
||||
|
||||
if (info.dir != PJMEDIA_DIR_CAPTURE)
|
||||
return PJ_EINVAL;
|
||||
|
||||
cap_dev = info.id;
|
||||
|
||||
/* The specified capture device is being used already */
|
||||
if (call_med->strm.v.cap_dev == cap_dev)
|
||||
return PJ_SUCCESS;
|
||||
|
||||
/* == Apply the new capture device == */
|
||||
|
||||
wid = call_med->strm.v.cap_win_id;
|
||||
w = &pjsua_var.win[wid];
|
||||
pj_assert(w->type == PJSUA_WND_TYPE_PREVIEW && w->vp_cap);
|
||||
|
||||
status = pjmedia_vid_stream_get_port(call_med->strm.v.stream,
|
||||
PJMEDIA_DIR_ENCODING, &media_port);
|
||||
if (status != PJ_SUCCESS)
|
||||
return status;
|
||||
|
||||
/* = Detach stream port from the old capture device = */
|
||||
status = pjmedia_vid_port_disconnect(w->vp_cap);
|
||||
if (status != PJ_SUCCESS)
|
||||
return status;
|
||||
|
||||
status = pjmedia_vid_tee_remove_dst_port(w->tee, media_port);
|
||||
if (status != PJ_SUCCESS) {
|
||||
/* Connect back the old capturer */
|
||||
pjmedia_vid_port_connect(w->vp_cap, media_port, PJ_FALSE);
|
||||
return status;
|
||||
}
|
||||
|
||||
/* = Attach stream port to the new capture device = */
|
||||
|
||||
/* Create preview video window */
|
||||
status = create_vid_win(PJSUA_WND_TYPE_PREVIEW,
|
||||
&media_port->info.fmt,
|
||||
call_med->strm.v.rdr_dev,
|
||||
cap_dev,
|
||||
PJ_FALSE,
|
||||
&new_wid);
|
||||
if (status != PJ_SUCCESS)
|
||||
goto on_error;
|
||||
|
||||
inc_vid_win(new_wid);
|
||||
new_w = &pjsua_var.win[new_wid];
|
||||
|
||||
/* Connect stream to capturer (via video window tee) */
|
||||
status = pjmedia_vid_tee_add_dst_port2(new_w->tee, 0, media_port);
|
||||
if (status != PJ_SUCCESS)
|
||||
goto on_error;
|
||||
|
||||
/* Connect capturer to tee */
|
||||
status = pjmedia_vid_port_connect(new_w->vp_cap, new_w->tee, PJ_FALSE);
|
||||
if (status != PJ_SUCCESS)
|
||||
return status;
|
||||
|
||||
/* Start renderer */
|
||||
status = pjmedia_vid_port_start(new_w->vp_rend);
|
||||
if (status != PJ_SUCCESS)
|
||||
goto on_error;
|
||||
|
||||
/* Start capturer */
|
||||
status = pjmedia_vid_port_start(new_w->vp_cap);
|
||||
if (status != PJ_SUCCESS)
|
||||
goto on_error;
|
||||
|
||||
/* Finally */
|
||||
call_med->strm.v.cap_dev = cap_dev;
|
||||
call_med->strm.v.cap_win_id = new_wid;
|
||||
dec_vid_win(wid);
|
||||
|
||||
return PJ_SUCCESS;
|
||||
|
||||
on_error:
|
||||
if (new_w) {
|
||||
/* Disconnect media port from the new capturer */
|
||||
pjmedia_vid_tee_remove_dst_port(new_w->tee, media_port);
|
||||
/* Release the new capturer */
|
||||
dec_vid_win(new_wid);
|
||||
}
|
||||
|
||||
/* Revert back to the old capturer */
|
||||
status = pjmedia_vid_tee_add_dst_port2(w->tee, 0, media_port);
|
||||
if (status != PJ_SUCCESS)
|
||||
return status;
|
||||
|
||||
status = pjmedia_vid_port_connect(w->vp_cap, w->tee, PJ_FALSE);
|
||||
if (status != PJ_SUCCESS)
|
||||
return status;
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
/* Start transmitting video stream in a call */
|
||||
static pj_status_t call_start_tx_video(pjsua_call *call,
|
||||
int med_idx,
|
||||
pjmedia_vid_dev_index cap_dev)
|
||||
{
|
||||
pjsua_call_media *call_med;
|
||||
pj_status_t status;
|
||||
|
||||
/* Verify and normalize media index */
|
||||
if (med_idx == -1) {
|
||||
int first_active;
|
||||
|
||||
call_get_vid_strm_info(call, &first_active, NULL, NULL, NULL);
|
||||
if (first_active == -1)
|
||||
return PJ_ENOTFOUND;
|
||||
|
||||
med_idx = first_active;
|
||||
}
|
||||
|
||||
call_med = &call->media[med_idx];
|
||||
|
||||
/* Verify if the stream is transmitting video */
|
||||
if (call_med->type != PJMEDIA_TYPE_VIDEO ||
|
||||
(call_med->dir & PJMEDIA_DIR_ENCODING) == 0)
|
||||
{
|
||||
return PJ_EINVAL;
|
||||
}
|
||||
|
||||
/* Apply the new capture device */
|
||||
status = call_modify_video(call, med_idx, cap_dev);
|
||||
if (status != PJ_SUCCESS)
|
||||
return status;
|
||||
|
||||
/* Start stream in encoding direction */
|
||||
status = pjmedia_vid_stream_resume(call_med->strm.v.stream,
|
||||
PJMEDIA_DIR_ENCODING);
|
||||
if (status != PJ_SUCCESS)
|
||||
return status;
|
||||
|
||||
return PJ_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/* Stop transmitting video stream in a call */
|
||||
static pj_status_t call_stop_tx_video(pjsua_call *call,
|
||||
int med_idx)
|
||||
{
|
||||
pjsua_call_media *call_med;
|
||||
pj_status_t status;
|
||||
|
||||
/* Verify and normalize media index */
|
||||
if (med_idx == -1) {
|
||||
int first_active;
|
||||
|
||||
call_get_vid_strm_info(call, &first_active, NULL, NULL, NULL);
|
||||
if (first_active == -1)
|
||||
return PJ_ENOTFOUND;
|
||||
|
||||
med_idx = first_active;
|
||||
}
|
||||
|
||||
call_med = &call->media[med_idx];
|
||||
|
||||
/* Verify if the stream is transmitting video */
|
||||
if (call_med->type != PJMEDIA_TYPE_VIDEO ||
|
||||
(call_med->dir & PJMEDIA_DIR_ENCODING) == 0)
|
||||
{
|
||||
return PJ_EINVAL;
|
||||
}
|
||||
|
||||
/* Pause stream in encoding direction */
|
||||
status = pjmedia_vid_stream_pause( call_med->strm.v.stream,
|
||||
PJMEDIA_DIR_ENCODING);
|
||||
if (status != PJ_SUCCESS)
|
||||
return status;
|
||||
|
||||
return PJ_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Start, stop, and/or manipulate video transmission for the specified call.
|
||||
*/
|
||||
PJ_DEF(pj_status_t) pjsua_call_set_vid_strm (
|
||||
pjsua_call_id call_id,
|
||||
pjsua_call_vid_strm_op op,
|
||||
const pjsua_call_vid_strm_op_param *param)
|
||||
{
|
||||
pjsua_call *call;
|
||||
pjsua_call_vid_strm_op_param param_;
|
||||
pj_status_t status;
|
||||
|
||||
PJ_ASSERT_RETURN(call_id>=0 && call_id<(int)pjsua_var.ua_cfg.max_calls,
|
||||
PJ_EINVAL);
|
||||
|
||||
PJSUA_LOCK();
|
||||
|
||||
call = &pjsua_var.calls[call_id];
|
||||
|
||||
if (param) {
|
||||
param_ = *param;
|
||||
} else {
|
||||
param_.med_idx = -1;
|
||||
param_.cap_dev = PJMEDIA_VID_DEFAULT_CAPTURE_DEV;
|
||||
}
|
||||
|
||||
/* Get real capture ID, if set to PJMEDIA_VID_DEFAULT_CAPTURE_DEV */
|
||||
if (param_.cap_dev == PJMEDIA_VID_DEFAULT_CAPTURE_DEV) {
|
||||
pjmedia_vid_dev_info info;
|
||||
pjmedia_vid_dev_get_info(param_.cap_dev, &info);
|
||||
param_.cap_dev = info.id;
|
||||
}
|
||||
|
||||
switch (op) {
|
||||
case PJSUA_CALL_VID_STRM_ADD:
|
||||
status = call_add_video(call, param_.cap_dev);
|
||||
break;
|
||||
case PJSUA_CALL_VID_STRM_REMOVE:
|
||||
status = call_remove_video(call, param_.med_idx);
|
||||
break;
|
||||
case PJSUA_CALL_VID_STRM_MODIFY:
|
||||
status = call_modify_video(call, param_.med_idx, param_.cap_dev);
|
||||
break;
|
||||
case PJSUA_CALL_VID_STRM_START_TRANSMIT:
|
||||
status = call_start_tx_video(call, param_.med_idx, param_.cap_dev);
|
||||
break;
|
||||
case PJSUA_CALL_VID_STRM_STOP_TRANSMIT:
|
||||
status = call_stop_tx_video(call, param_.med_idx);
|
||||
break;
|
||||
default:
|
||||
status = PJ_EINVALIDOP;
|
||||
break;
|
||||
}
|
||||
|
||||
PJSUA_UNLOCK();
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
#endif /* PJSUA_HAS_VIDEO */
|
||||
|
||||
|
|
Loading…
Reference in New Issue