summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBenny Prijono <bennylp@teluu.com>2011-09-20 10:07:55 +0000
committerBenny Prijono <bennylp@teluu.com>2011-09-20 10:07:55 +0000
commitbe8d37186b16150716f752883ae6857a0161db40 (patch)
tree269fb1f2c16f90e539cf9534163dde56594bcb89
parentb9aa69da263759ce63593adae3327b8de25cd388 (diff)
Related to preview (re #1340): handle problems with starting or stopping preview during a call
git-svn-id: http://svn.pjsip.org/repos/pjproject/trunk@3758 74dad513-b988-da41-8d7b-12977e46ad98
-rw-r--r--pjmedia/include/pjmedia-videodev/videodev.h42
-rw-r--r--pjmedia/include/pjmedia-videodev/videodev_imp.h3
-rw-r--r--pjmedia/include/pjmedia/vid_port.h9
-rw-r--r--pjmedia/src/pjmedia-videodev/videodev.c14
-rw-r--r--pjmedia/src/pjmedia/vid_port.c5
-rw-r--r--pjsip/include/pjsua-lib/pjsua_internal.h1
-rw-r--r--pjsip/src/pjsua-lib/pjsua_vid.c112
7 files changed, 164 insertions, 22 deletions
diff --git a/pjmedia/include/pjmedia-videodev/videodev.h b/pjmedia/include/pjmedia-videodev/videodev.h
index 30a9750b..0c3d4c82 100644
--- a/pjmedia/include/pjmedia-videodev/videodev.h
+++ b/pjmedia/include/pjmedia-videodev/videodev.h
@@ -220,7 +220,13 @@ typedef struct pjmedia_vid_dev_info
*/
pjmedia_dir dir;
- /** Specify whether the device supports callback */
+ /**
+ * Specify whether the device supports callback. Devices that implement
+ * "active interface" will actively call the callbacks to give or ask for
+ * video frames. If the device doesn't support callback, application
+ * must actively request or give video frames from/to the device by using
+ * pjmedia_vid_dev_stream_get_frame()/pjmedia_vid_dev_stream_put_frame().
+ */
pj_bool_t has_callback;
/** Device capabilities, as bitmask combination of #pjmedia_vid_dev_cap */
@@ -641,6 +647,16 @@ PJ_DECL(pj_status_t) pjmedia_vid_dev_stream_start(
pjmedia_vid_dev_stream *strm);
/**
+ * Query whether the stream has been started.
+ *
+ * @param strm The video stream
+ *
+ * @return PJ_TRUE if the video stream has been started.
+ */
+PJ_DECL(pj_bool_t) pjmedia_vid_dev_stream_is_running(pjmedia_vid_dev_stream *strm);
+
+
+/**
* Get the event publisher object for the video stream. Caller typically use
* the returned object to subscribe or unsubscribe events from the video
* stream.
@@ -652,11 +668,33 @@ PJ_DECL(pj_status_t) pjmedia_vid_dev_stream_start(
PJ_DECL(pjmedia_event_publisher*)
pjmedia_vid_dev_stream_get_event_publisher(pjmedia_vid_dev_stream *strm);
-/* Get/put frame API for passive stream */
+
+/**
+ * Request one frame from the stream. Application needs to call this function
+ * periodically only if the stream doesn't support "active interface", i.e.
+ * the pjmedia_vid_dev_info.has_callback member is PJ_FALSE.
+ *
+ * @param strm The video stream.
+ * @param frame The video frame to be filled by the device.
+ *
+ * @return PJ_SUCCESS on successful operation or the appropriate
+ * error code.
+ */
PJ_DECL(pj_status_t) pjmedia_vid_dev_stream_get_frame(
pjmedia_vid_dev_stream *strm,
pjmedia_frame *frame);
+/**
+ * Put one frame to the stream. Application needs to call this function
+ * periodically only if the stream doesn't support "active interface", i.e.
+ * the pjmedia_vid_dev_info.has_callback member is PJ_FALSE.
+ *
+ * @param strm The video stream.
+ * @param frame The video frame to put to the device.
+ *
+ * @return PJ_SUCCESS on successful operation or the appropriate
+ * error code.
+ */
PJ_DECL(pj_status_t) pjmedia_vid_dev_stream_put_frame(
pjmedia_vid_dev_stream *strm,
const pjmedia_frame *frame);
diff --git a/pjmedia/include/pjmedia-videodev/videodev_imp.h b/pjmedia/include/pjmedia-videodev/videodev_imp.h
index 90dcc580..8ddfd968 100644
--- a/pjmedia/include/pjmedia-videodev/videodev_imp.h
+++ b/pjmedia/include/pjmedia-videodev/videodev_imp.h
@@ -181,6 +181,9 @@ struct pjmedia_vid_dev_stream
struct {
/** Driver index */
unsigned drv_idx;
+
+ /** Has it been started? */
+ pj_bool_t is_running;
} sys;
/** Operations */
diff --git a/pjmedia/include/pjmedia/vid_port.h b/pjmedia/include/pjmedia/vid_port.h
index b7fa5666..66c31c84 100644
--- a/pjmedia/include/pjmedia/vid_port.h
+++ b/pjmedia/include/pjmedia/vid_port.h
@@ -213,6 +213,15 @@ pjmedia_vid_port_get_connected_port(pjmedia_vid_port *vid_port);
PJ_DECL(pj_status_t) pjmedia_vid_port_start(pjmedia_vid_port *vid_port);
/**
+ * Query whether the video port has been started.
+ *
+ * @param vid_port The video port.
+ *
+ * @return PJ_TRUE if the video port has been started.
+ */
+PJ_DECL(pj_bool_t) pjmedia_vid_port_is_running(pjmedia_vid_port *vid_port);
+
+/**
* Stop the video port.
*
* @param vid_port The video port.
diff --git a/pjmedia/src/pjmedia-videodev/videodev.c b/pjmedia/src/pjmedia-videodev/videodev.c
index a88e91c4..f2523d79 100644
--- a/pjmedia/src/pjmedia-videodev/videodev.c
+++ b/pjmedia/src/pjmedia-videodev/videodev.c
@@ -781,7 +781,17 @@ pjmedia_vid_dev_stream_get_event_publisher(pjmedia_vid_dev_stream *strm)
/* API: Start the stream. */
PJ_DEF(pj_status_t) pjmedia_vid_dev_stream_start(pjmedia_vid_dev_stream *strm)
{
- return strm->op->start(strm);
+ pj_status_t status = strm->op->start(strm);
+ if (status == PJ_SUCCESS)
+ strm->sys.is_running = PJ_TRUE;
+ return status;
+}
+
+/* API: has it been started? */
+PJ_DEF(pj_bool_t)
+pjmedia_vid_dev_stream_is_running(pjmedia_vid_dev_stream *strm)
+{
+ return strm->sys.is_running;
}
PJ_DEF(pj_status_t) pjmedia_vid_dev_stream_get_frame(
@@ -803,6 +813,7 @@ PJ_DEF(pj_status_t) pjmedia_vid_dev_stream_put_frame(
/* API: Stop the stream. */
PJ_DEF(pj_status_t) pjmedia_vid_dev_stream_stop(pjmedia_vid_dev_stream *strm)
{
+ strm->sys.is_running = PJ_FALSE;
return strm->op->stop(strm);
}
@@ -810,6 +821,7 @@ PJ_DEF(pj_status_t) pjmedia_vid_dev_stream_stop(pjmedia_vid_dev_stream *strm)
PJ_DEF(pj_status_t) pjmedia_vid_dev_stream_destroy(
pjmedia_vid_dev_stream *strm)
{
+ strm->sys.is_running = PJ_FALSE;
return strm->op->destroy(strm);
}
diff --git a/pjmedia/src/pjmedia/vid_port.c b/pjmedia/src/pjmedia/vid_port.c
index 56694cd7..fa5c2da6 100644
--- a/pjmedia/src/pjmedia/vid_port.c
+++ b/pjmedia/src/pjmedia/vid_port.c
@@ -479,6 +479,11 @@ on_error:
return status;
}
+PJ_DEF(pj_bool_t) pjmedia_vid_port_is_running(pjmedia_vid_port *vp)
+{
+ return pjmedia_vid_dev_stream_is_running(vp->strm);
+}
+
PJ_DEF(pj_status_t) pjmedia_vid_port_stop(pjmedia_vid_port *vp)
{
pj_status_t status;
diff --git a/pjsip/include/pjsua-lib/pjsua_internal.h b/pjsip/include/pjsua-lib/pjsua_internal.h
index 46547eec..01d32887 100644
--- a/pjsip/include/pjsua-lib/pjsua_internal.h
+++ b/pjsip/include/pjsua-lib/pjsua_internal.h
@@ -324,6 +324,7 @@ typedef struct pjsua_vid_win
pjmedia_vid_port *vp_rend; /**< Renderer vidport */
pjmedia_port *tee; /**< Video tee */
pjmedia_vid_dev_index preview_cap_id;/**< Capture dev id */
+ pj_bool_t preview_running;/**< Preview is started*/
pj_bool_t is_native; /**< Preview is by dev */
} pjsua_vid_win;
diff --git a/pjsip/src/pjsua-lib/pjsua_vid.c b/pjsip/src/pjsua-lib/pjsua_vid.c
index 5c25bb64..55f892ec 100644
--- a/pjsip/src/pjsua-lib/pjsua_vid.c
+++ b/pjsip/src/pjsua-lib/pjsua_vid.c
@@ -323,10 +323,8 @@ PJ_DEF(pj_status_t) pjsua_vid_codec_set_param(
* Preview
*/
-/*
- * Get the preview window handle associated with the capture device, if any.
- */
-PJ_DEF(pjsua_vid_win_id) pjsua_vid_preview_get_win(pjmedia_vid_dev_index id)
+static pjsua_vid_win_id vid_preview_get_win(pjmedia_vid_dev_index id,
+ pj_bool_t running_only)
{
pjsua_vid_win_id wid = PJSUA_INVALID_ID;
unsigned i;
@@ -347,11 +345,27 @@ PJ_DEF(pjsua_vid_win_id) pjsua_vid_preview_get_win(pjmedia_vid_dev_index id)
break;
}
}
+
+ if (wid != PJSUA_INVALID_ID && running_only) {
+ pjsua_vid_win *w = &pjsua_var.win[wid];
+ wid = w->preview_running ? wid : PJSUA_INVALID_ID;
+ }
+
PJSUA_UNLOCK();
return wid;
}
+/*
+ * NOTE: internal function don't use this!!! Use vid_preview_get_win()
+ * instead. This is because this function will only return window ID
+ * if preview is currently running.
+ */
+PJ_DEF(pjsua_vid_win_id) pjsua_vid_preview_get_win(pjmedia_vid_dev_index id)
+{
+ return vid_preview_get_win(id, PJ_TRUE);
+}
+
PJ_DEF(void) pjsua_vid_win_reset(pjsua_vid_win_id wid)
{
pjsua_vid_win *w = &pjsua_var.win[wid];
@@ -393,7 +407,7 @@ static pj_status_t create_vid_win(pjsua_vid_win_type type,
/* If type is preview, check if it exists already */
if (type == PJSUA_WND_TYPE_PREVIEW) {
- wid = pjsua_vid_preview_get_win(cap_id);
+ wid = vid_preview_get_win(cap_id, PJ_FALSE);
if (wid != PJSUA_INVALID_ID) {
/* Yes, it exists */
/* Show/hide window */
@@ -420,9 +434,9 @@ static pj_status_t create_vid_win(pjsua_vid_win_type type,
/* Done */
*id = wid;
- PJ_LOG(4,(THIS_FILE, "Window already exist: %d", wid));
pj_log_pop_indent();
- return PJ_SUCCESS;
+
+ return status;
}
}
@@ -825,7 +839,12 @@ pj_status_t video_channel_update(pjsua_call_media *call_med,
goto on_error;
}
- wid = pjsua_vid_preview_get_win(call_med->strm.v.cap_dev);
+ /* Note: calling pjsua_vid_preview_get_win() even though
+ * create_vid_win() will automatically create the window
+ * if it doesn't exist, because create_vid_win() will modify
+ * existing window SHOW/HIDE value.
+ */
+ wid = vid_preview_get_win(call_med->strm.v.cap_dev, PJ_FALSE);
if (wid == PJSUA_INVALID_ID) {
/* Create preview video window */
status = create_vid_win(PJSUA_WND_TYPE_PREVIEW,
@@ -1042,9 +1061,30 @@ PJ_DEF(pj_status_t) pjsua_vid_preview_start(pjmedia_vid_dev_index id,
}
w = &pjsua_var.win[wid];
+ if (w->preview_running) {
+ PJSUA_UNLOCK();
+ pj_log_pop_indent();
+ return PJ_SUCCESS;
+ }
/* Start renderer, unless it's native preview */
- if (!w->is_native) {
+ if (w->is_native && !pjmedia_vid_port_is_running(w->vp_cap)) {
+ pjmedia_vid_dev_stream *cap_dev;
+ pj_bool_t enabled = PJ_TRUE;
+
+ cap_dev = pjmedia_vid_port_get_stream(w->vp_cap);
+ status = pjmedia_vid_dev_stream_set_cap(
+ cap_dev, PJMEDIA_VID_DEV_CAP_INPUT_PREVIEW,
+ &enabled);
+ if (status != PJ_SUCCESS) {
+ PJ_PERROR(1,(THIS_FILE, status,
+ "Error activating native preview, falling back "
+ "to software preview.."));
+ w->is_native = PJ_FALSE;
+ }
+ }
+
+ if (!w->is_native && !pjmedia_vid_port_is_running(w->vp_rend)) {
status = pjmedia_vid_port_start(w->vp_rend);
if (status != PJ_SUCCESS) {
PJSUA_UNLOCK();
@@ -1054,14 +1094,17 @@ PJ_DEF(pj_status_t) pjsua_vid_preview_start(pjmedia_vid_dev_index id,
}
/* Start capturer */
- status = pjmedia_vid_port_start(w->vp_cap);
- if (status != PJ_SUCCESS) {
- PJSUA_UNLOCK();
- pj_log_pop_indent();
- return status;
+ if (!pjmedia_vid_port_is_running(w->vp_cap)) {
+ status = pjmedia_vid_port_start(w->vp_cap);
+ if (status != PJ_SUCCESS) {
+ PJSUA_UNLOCK();
+ pj_log_pop_indent();
+ return status;
+ }
}
inc_vid_win(wid);
+ w->preview_running = PJ_TRUE;
PJSUA_UNLOCK();
pj_log_pop_indent();
@@ -1074,9 +1117,8 @@ PJ_DEF(pj_status_t) pjsua_vid_preview_start(pjmedia_vid_dev_index id,
PJ_DEF(pj_status_t) pjsua_vid_preview_stop(pjmedia_vid_dev_index id)
{
pjsua_vid_win_id wid = PJSUA_INVALID_ID;
-
- PJ_LOG(4,(THIS_FILE, "Stopping preview for cap_dev=%d", id));
- pj_log_push_indent();
+ pjsua_vid_win *w;
+ pj_status_t status;
PJSUA_LOCK();
wid = pjsua_vid_preview_get_win(id);
@@ -1086,7 +1128,34 @@ PJ_DEF(pj_status_t) pjsua_vid_preview_stop(pjmedia_vid_dev_index id)
return PJ_ENOTFOUND;
}
- dec_vid_win(wid);
+ PJ_LOG(4,(THIS_FILE, "Stopping preview for cap_dev=%d", id));
+ pj_log_push_indent();
+
+ w = &pjsua_var.win[wid];
+ if (w->preview_running) {
+ if (w->is_native) {
+ pjmedia_vid_dev_stream *cap_dev;
+ pj_bool_t enabled = PJ_FALSE;
+
+ cap_dev = pjmedia_vid_port_get_stream(w->vp_cap);
+ status = pjmedia_vid_dev_stream_set_cap(
+ cap_dev, PJMEDIA_VID_DEV_CAP_INPUT_PREVIEW,
+ &enabled);
+ } else {
+ status = pjmedia_vid_port_stop(w->vp_rend);
+ }
+
+ if (status != PJ_SUCCESS) {
+ PJ_PERROR(1,(THIS_FILE, status, "Error stopping %spreview",
+ (w->is_native ? "native " : "")));
+ PJSUA_UNLOCK();
+ pj_log_pop_indent();
+ return status;
+ }
+
+ dec_vid_win(wid);
+ w->preview_running = PJ_FALSE;
+ }
PJSUA_UNLOCK();
pj_log_pop_indent();
@@ -1673,7 +1742,12 @@ static pj_status_t call_change_cap_dev(pjsua_call *call,
/* = Attach stream port to the new capture device = */
- new_wid = pjsua_vid_preview_get_win(cap_dev);
+ /* Note: calling pjsua_vid_preview_get_win() even though
+ * create_vid_win() will automatically create the window
+ * if it doesn't exist, because create_vid_win() will modify
+ * existing window SHOW/HIDE value.
+ */
+ new_wid = vid_preview_get_win(cap_dev, PJ_FALSE);
if (new_wid == PJSUA_INVALID_ID) {
/* Create preview video window */
status = create_vid_win(PJSUA_WND_TYPE_PREVIEW,