summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--pjsip-apps/src/swig/java/android/res/layout/activity_call.xml61
-rw-r--r--pjsip-apps/src/swig/java/android/res/values/strings.xml3
-rw-r--r--pjsip-apps/src/swig/java/android/src/org/pjsip/pjsua2/app/CallActivity.java139
-rw-r--r--pjsip-apps/src/swig/java/android/src/org/pjsip/pjsua2/app/MyApp.java2
-rw-r--r--pjsip/include/pjsua2/media.hpp99
-rw-r--r--pjsip/src/pjsua2/media.cpp82
6 files changed, 350 insertions, 36 deletions
diff --git a/pjsip-apps/src/swig/java/android/res/layout/activity_call.xml b/pjsip-apps/src/swig/java/android/res/layout/activity_call.xml
index 63d90a02..17acf1c5 100644
--- a/pjsip-apps/src/swig/java/android/res/layout/activity_call.xml
+++ b/pjsip-apps/src/swig/java/android/res/layout/activity_call.xml
@@ -23,24 +23,51 @@
android:layout_height="wrap_content"
android:gravity="center"
android:text="Call state" />
-
- <Button
- android:id="@+id/buttonAccept"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:onClick="acceptCall"
- android:text="Accept" />
-
- <Button
- android:id="@+id/buttonHangup"
+
+ <LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:onClick="hangupCall"
- android:text="Reject" />
-
+ android:orientation="horizontal">
+
+ <LinearLayout
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ android:layout_weight=".50">
+
+ <Button
+ android:id="@+id/buttonAccept"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:onClick="acceptCall"
+ android:text="Accept" />
+
+ <Button
+ android:id="@+id/buttonHangup"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:onClick="hangupCall"
+ android:text="Reject" />
+
+ <Button
+ android:id="@+id/buttonShowPreview"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:onClick="showPreview"
+ android:text="@+string/show_preview" />
+
+ </LinearLayout>
+ <SurfaceView
+ android:id="@+id/surfacePreviewCapture"
+ android:layout_width="0dp"
+ android:layout_height="match_parent"
+ android:layout_weight=".50" />
+
+ </LinearLayout>
+
<SurfaceView
- android:id="@+id/surfaceIncomingVideo"
- android:layout_width="match_parent"
- android:layout_height="match_parent" />
-
+ android:id="@+id/surfaceIncomingVideo"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent" />
+
</LinearLayout> \ No newline at end of file
diff --git a/pjsip-apps/src/swig/java/android/res/values/strings.xml b/pjsip-apps/src/swig/java/android/res/values/strings.xml
index 2ee52b69..cce48a16 100644
--- a/pjsip-apps/src/swig/java/android/res/values/strings.xml
+++ b/pjsip-apps/src/swig/java/android/res/values/strings.xml
@@ -5,5 +5,6 @@
<string name="action_settings">Settings</string>
<string name="title_activity_call">Call</string>
<string name="hello_world">Hello world!</string>
-
+ <string name="show_preview">Show Preview</string>
+ <string name="hide_preview">Hide Preview</string>
</resources>
diff --git a/pjsip-apps/src/swig/java/android/src/org/pjsip/pjsua2/app/CallActivity.java b/pjsip-apps/src/swig/java/android/src/org/pjsip/pjsua2/app/CallActivity.java
index b74b3cd5..91123be7 100644
--- a/pjsip-apps/src/swig/java/android/src/org/pjsip/pjsua2/app/CallActivity.java
+++ b/pjsip-apps/src/swig/java/android/src/org/pjsip/pjsua2/app/CallActivity.java
@@ -30,11 +30,66 @@ import android.app.Activity;
import org.pjsip.pjsua2.*;
+class VideoPreviewHandler implements SurfaceHolder.Callback
+{
+ public boolean videoPreviewActive = false;
+
+ public void updateVideoPreview(SurfaceHolder holder)
+ {
+ if (MainActivity.currentCall != null &&
+ MainActivity.currentCall.vidWin != null &&
+ MainActivity.currentCall.vidPrev != null)
+ {
+ if (videoPreviewActive) {
+ VideoWindowHandle vidWH = new VideoWindowHandle();
+ vidWH.getHandle().setWindow(holder.getSurface());
+ VideoPreviewOpParam vidPrevParam = new VideoPreviewOpParam();
+ vidPrevParam.setWindow(vidWH);
+ try {
+ MainActivity.currentCall.vidPrev.start(vidPrevParam);
+ } catch (Exception e) {
+ System.out.println(e);
+ }
+ } else {
+ try {
+ MainActivity.currentCall.vidPrev.stop();
+ } catch (Exception e) {
+ System.out.println(e);
+ }
+ }
+ }
+ }
+
+ @Override
+ public void surfaceChanged(SurfaceHolder holder, int format, int w, int h)
+ {
+ updateVideoPreview(holder);
+ }
+
+ @Override
+ public void surfaceCreated(SurfaceHolder holder)
+ {
+
+ }
+
+ @Override
+ public void surfaceDestroyed(SurfaceHolder holder)
+ {
+ try {
+ MainActivity.currentCall.vidPrev.stop();
+ } catch (Exception e) {
+ System.out.println(e);
+ }
+ }
+}
+
public class CallActivity extends Activity
implements Handler.Callback, SurfaceHolder.Callback
{
public static Handler handler_;
+ private static VideoPreviewHandler previewHandler =
+ new VideoPreviewHandler();
private final Handler handler = new Handler(this);
private static CallInfo lastCallInfo;
@@ -45,14 +100,22 @@ public class CallActivity extends Activity
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_call);
- SurfaceView surfaceView = (SurfaceView)
+ SurfaceView surfaceInVideo = (SurfaceView)
findViewById(R.id.surfaceIncomingVideo);
+ SurfaceView surfacePreview = (SurfaceView)
+ findViewById(R.id.surfacePreviewCapture);
+ Button buttonShowPreview = (Button)
+ findViewById(R.id.buttonShowPreview);
+
if (MainActivity.currentCall == null ||
MainActivity.currentCall.vidWin == null)
{
- surfaceView.setVisibility(View.GONE);
+ surfaceInVideo.setVisibility(View.GONE);
+ buttonShowPreview.setVisibility(View.GONE);
}
- surfaceView.getHolder().addCallback(this);
+ setupVideoPreview(surfacePreview, buttonShowPreview);
+ surfaceInVideo.getHolder().addCallback(this);
+ surfacePreview.getHolder().addCallback(previewHandler);
handler_ = handler;
if (MainActivity.currentCall != null) {
@@ -73,26 +136,34 @@ public class CallActivity extends Activity
super.onDestroy();
handler_ = null;
}
-
- private void updateVideoWindow(SurfaceHolder holder)
- {
+
+ private void updateVideoWindow(boolean show)
+ {
if (MainActivity.currentCall != null &&
- MainActivity.currentCall.vidWin != null)
+ MainActivity.currentCall.vidWin != null &&
+ MainActivity.currentCall.vidPrev != null)
{
- VideoWindowHandle vidWH = new VideoWindowHandle();
- if (holder == null)
+ SurfaceView surfaceInVideo = (SurfaceView)
+ findViewById(R.id.surfaceIncomingVideo);
+
+ VideoWindowHandle vidWH = new VideoWindowHandle();
+ if (show) {
+ vidWH.getHandle().setWindow(
+ surfaceInVideo.getHolder().getSurface());
+ } else {
vidWH.getHandle().setWindow(null);
- else
- vidWH.getHandle().setWindow(holder.getSurface());
+ }
try {
MainActivity.currentCall.vidWin.setWindow(vidWH);
- } catch (Exception e) {}
+ } catch (Exception e) {
+ System.out.println(e);
+ }
}
}
-
+
public void surfaceChanged(SurfaceHolder holder, int format, int w, int h)
{
- updateVideoWindow(holder);
+ updateVideoWindow(true);
}
public void surfaceCreated(SurfaceHolder holder)
@@ -101,7 +172,7 @@ public class CallActivity extends Activity
public void surfaceDestroyed(SurfaceHolder holder)
{
- updateVideoWindow(null);
+ updateVideoWindow(false);
}
public void acceptCall(View view)
@@ -132,13 +203,45 @@ public class CallActivity extends Activity
}
}
}
+
+ public void setupVideoPreview(SurfaceView surfacePreview,
+ Button buttonShowPreview)
+ {
+ surfacePreview.setVisibility(previewHandler.videoPreviewActive?
+ View.VISIBLE:View.GONE);
+
+ buttonShowPreview.setText(previewHandler.videoPreviewActive?
+ getString(R.string.hide_preview):
+ getString(R.string.show_preview));
+ }
+
+ public void showPreview(View view)
+ {
+ SurfaceView surfacePreview = (SurfaceView)
+ findViewById(R.id.surfacePreviewCapture);
+
+ Button buttonShowPreview = (Button)
+ findViewById(R.id.buttonShowPreview);
+
+
+ previewHandler.videoPreviewActive = !previewHandler.videoPreviewActive;
+
+ setupVideoPreview(surfacePreview, buttonShowPreview);
+
+ previewHandler.updateVideoPreview(surfacePreview.getHolder());
+ }
private void setupVideoSurface()
{
- SurfaceView surfaceView = (SurfaceView)
+ SurfaceView surfaceInVideo = (SurfaceView)
findViewById(R.id.surfaceIncomingVideo);
- surfaceView.setVisibility(View.VISIBLE);
- updateVideoWindow(surfaceView.getHolder());
+ SurfaceView surfacePreview = (SurfaceView)
+ findViewById(R.id.surfacePreviewCapture);
+ Button buttonShowPreview = (Button)
+ findViewById(R.id.buttonShowPreview);
+ surfaceInVideo.setVisibility(View.VISIBLE);
+ buttonShowPreview.setVisibility(View.VISIBLE);
+ surfacePreview.setVisibility(View.GONE);
}
@Override
diff --git a/pjsip-apps/src/swig/java/android/src/org/pjsip/pjsua2/app/MyApp.java b/pjsip-apps/src/swig/java/android/src/org/pjsip/pjsua2/app/MyApp.java
index 846235d5..d4fbc307 100644
--- a/pjsip-apps/src/swig/java/android/src/org/pjsip/pjsua2/app/MyApp.java
+++ b/pjsip-apps/src/swig/java/android/src/org/pjsip/pjsua2/app/MyApp.java
@@ -49,6 +49,7 @@ class MyLogWriter extends LogWriter
class MyCall extends Call
{
public VideoWindow vidWin;
+ public VideoPreview vidPrev;
MyCall(MyAccount acc, int call_id)
{
@@ -112,6 +113,7 @@ class MyCall extends Call
cmi.getVideoIncomingWindowId() != pjsua2.INVALID_ID)
{
vidWin = new VideoWindow(cmi.getVideoIncomingWindowId());
+ vidPrev = new VideoPreview(cmi.getVideoCapDev());
}
}
diff --git a/pjsip/include/pjsua2/media.hpp b/pjsip/include/pjsua2/media.hpp
index 181001e4..16df4ca5 100644
--- a/pjsip/include/pjsua2/media.hpp
+++ b/pjsip/include/pjsua2/media.hpp
@@ -1488,6 +1488,105 @@ private:
pjsua_vid_win_id winId;
};
+/**
+ * This structure contains parameters for VideoPreview::start()
+ */
+struct VideoPreviewOpParam {
+ /**
+ * Device ID for the video renderer to be used for rendering the
+ * capture stream for preview. This parameter is ignored if native
+ * preview is being used.
+ *
+ * Default: PJMEDIA_VID_DEFAULT_RENDER_DEV
+ */
+ pjmedia_vid_dev_index rendId;
+
+ /**
+ * Show window initially.
+ *
+ * Default: PJ_TRUE.
+ */
+ bool show;
+
+ /**
+ * Window flags. The value is a bitmask combination of
+ * \a pjmedia_vid_dev_wnd_flag.
+ *
+ * Default: 0.
+ */
+ unsigned windowFlags;
+
+ /**
+ * Media format. If left unitialized, this parameter will not be used.
+ */
+ MediaFormat format;
+
+ /**
+ * Optional output window to be used to display the video preview.
+ * This parameter will only be used if the video device supports
+ * PJMEDIA_VID_DEV_CAP_OUTPUT_WINDOW capability and the capability
+ * is not read-only.
+ */
+ VideoWindowHandle window;
+
+public:
+ /**
+ * Default constructor initializes with default values.
+ */
+ VideoPreviewOpParam();
+
+ /**
+ * Convert from pjsip
+ */
+ void fromPj(const pjsua_vid_preview_param &prm);
+
+ /**
+ * Convert to pjsip
+ */
+ pjsua_vid_preview_param toPj() const;
+};
+
+/**
+ * Video Preview
+ */
+class VideoPreview {
+public:
+ /**
+ * Constructor
+ */
+ VideoPreview(int dev_id);
+
+ /**
+ * Determine if the specified video input device has built-in native
+ * preview capability. This is a convenience function that is equal to
+ * querying device's capability for PJMEDIA_VID_DEV_CAP_INPUT_PREVIEW
+ * capability.
+ *
+ * @return true if it has.
+ */
+ bool hasNative();
+
+ /**
+ * Start video preview window for the specified capture device.
+ *
+ * @param p Video preview parameters.
+ */
+ void start(const VideoPreviewOpParam &param) throw(Error);
+
+ /**
+ * Stop video preview.
+ */
+ void stop() throw(Error);
+
+ /*
+ * Get the preview window handle associated with the capture device,if any.
+ */
+ VideoWindow getVideoWindow();
+
+private:
+ pjmedia_vid_dev_index devId;
+};
+
/*************************************************************************
* Codec management
*/
diff --git a/pjsip/src/pjsua2/media.cpp b/pjsip/src/pjsua2/media.cpp
index 18b75f13..12e67f52 100644
--- a/pjsip/src/pjsua2/media.cpp
+++ b/pjsip/src/pjsua2/media.cpp
@@ -1093,6 +1093,88 @@ void VideoWindow::setWindow(const VideoWindowHandle &win) throw(Error)
PJ_UNUSED_ARG(win);
#endif
}
+///////////////////////////////////////////////////////////////////////////////
+
+VideoPreviewOpParam::VideoPreviewOpParam()
+{
+#if PJSUA_HAS_VIDEO
+ pjsua_vid_preview_param vid_prev_param;
+
+ pjsua_vid_preview_param_default(&vid_prev_param);
+ fromPj(vid_prev_param);
+#endif
+}
+
+void VideoPreviewOpParam::fromPj(const pjsua_vid_preview_param &prm)
+{
+#if PJSUA_HAS_VIDEO
+ this->rendId = prm.rend_id;
+ this->show = PJ2BOOL(prm.show);
+ this->windowFlags = prm.wnd_flags;
+ this->format.id = prm.format.id;
+ this->format.type = prm.format.type;
+ this->window.type = prm.wnd.type;
+ this->window.handle.window = prm.wnd.info.window;
+#else
+ PJ_UNUSED_ARG(prm);
+#endif
+}
+
+pjsua_vid_preview_param VideoPreviewOpParam::toPj() const
+{
+ pjsua_vid_preview_param param;
+#if PJSUA_HAS_VIDEO
+ param.rend_id = this->rendId;
+ param.show = this->show;
+ param.wnd_flags = this->windowFlags;
+ param.format.id = this->format.id;
+ param.format.type = this->format.type;
+ param.wnd.type = this->window.type;
+ param.wnd.info.window = this->window.handle.window;
+#endif
+ return param;
+}
+
+VideoPreview::VideoPreview(int dev_id)
+: devId(dev_id)
+{
+
+}
+
+bool VideoPreview::hasNative()
+{
+#if PJSUA_HAS_VIDEO
+ return(PJ2BOOL(pjsua_vid_preview_has_native(devId)));
+#else
+ return false;
+#endif
+}
+
+void VideoPreview::start(const VideoPreviewOpParam &param) throw(Error)
+{
+#if PJSUA_HAS_VIDEO
+ pjsua_vid_preview_param prm = param.toPj();
+ PJSUA2_CHECK_EXPR(pjsua_vid_preview_start(devId, &prm));
+#else
+ PJ_UNUSED_ARG(param);
+#endif
+}
+
+void VideoPreview::stop() throw(Error)
+{
+#if PJSUA_HAS_VIDEO
+ pjsua_vid_preview_stop(devId);
+#endif
+}
+
+VideoWindow VideoPreview::getVideoWindow()
+{
+#if PJSUA_HAS_VIDEO
+ return (VideoWindow(pjsua_vid_preview_get_win(devId)));
+#else
+ return (VideoWindow(PJSUA_INVALID_ID));
+#endif
+}
///////////////////////////////////////////////////////////////////////////////
void CodecInfo::fromPj(const pjsua_codec_info &codec_info)