diff --git a/examples/androidnativeapi/AndroidManifest.xml b/examples/androidnativeapi/AndroidManifest.xml index 19e4dc0274..f10f55a1b6 100644 --- a/examples/androidnativeapi/AndroidManifest.xml +++ b/examples/androidnativeapi/AndroidManifest.xml @@ -5,6 +5,7 @@ + { nativeClient = nativeCreateClient(); }); } - public void call(VideoSink localSink, VideoSink remoteSink) { - handler.post(() -> { nativeCall(nativeClient, localSink, remoteSink); }); + public void call(VideoSink localSink, VideoSink remoteSink, VideoCapturer videoCapturer, + SurfaceTextureHelper videoCapturerSurfaceTextureHelper) { + handler.post(() -> { + nativeCall(nativeClient, localSink, remoteSink); + videoCapturer.initialize(videoCapturerSurfaceTextureHelper, applicationContext, + nativeGetJavaVideoCapturerObserver(nativeClient)); + videoCapturer.startCapture(CAPTURE_WIDTH, CAPTURE_HEIGHT, CAPTURE_FPS); + }); } public void hangup() { @@ -53,4 +71,7 @@ public class CallClient { private static native void nativeHangup(long nativePtr); @NativeClassQualifiedName("webrtc_examples::AndroidCallClient") private static native void nativeDelete(long nativePtr); + @NativeClassQualifiedName("webrtc_examples::AndroidCallClient") + private static native VideoCapturer.CapturerObserver nativeGetJavaVideoCapturerObserver( + long nativePtr); } diff --git a/examples/androidnativeapi/java/org/webrtc/examples/androidnativeapi/MainActivity.java b/examples/androidnativeapi/java/org/webrtc/examples/androidnativeapi/MainActivity.java index 173b797bc7..801e238782 100644 --- a/examples/androidnativeapi/java/org/webrtc/examples/androidnativeapi/MainActivity.java +++ b/examples/androidnativeapi/java/org/webrtc/examples/androidnativeapi/MainActivity.java @@ -11,19 +11,27 @@ package org.webrtc.examples.androidnativeapi; import android.app.Activity; +import android.content.Context; import android.os.Bundle; import android.widget.Button; import javax.annotation.Nullable; +import org.webrtc.Camera1Enumerator; +import org.webrtc.Camera2Enumerator; +import org.webrtc.CameraEnumerator; import org.webrtc.ContextUtils; import org.webrtc.EglBase; import org.webrtc.GlRectDrawer; +import org.webrtc.SurfaceTextureHelper; import org.webrtc.SurfaceViewRenderer; +import org.webrtc.VideoCapturer; public class MainActivity extends Activity { private @Nullable CallClient callClient; private @Nullable EglBase eglBase; private @Nullable SurfaceViewRenderer localRenderer; private @Nullable SurfaceViewRenderer remoteRenderer; + private @Nullable SurfaceTextureHelper videoCapturerSurfaceTextureHelper; + private @Nullable VideoCapturer videoCapturer; @Override protected void onCreate(Bundle savedInstance) { @@ -33,13 +41,19 @@ public class MainActivity extends Activity { setContentView(R.layout.activity_main); System.loadLibrary("examples_androidnativeapi_jni"); - callClient = new CallClient(); + callClient = new CallClient(getApplicationContext()); Button callButton = (Button) findViewById(R.id.call_button); - callButton.setOnClickListener((view) -> { callClient.call(localRenderer, remoteRenderer); }); + callButton.setOnClickListener((view) -> { + if (videoCapturer == null) { + videoCapturer = createVideoCapturer(getApplicationContext()); + } + callClient.call( + localRenderer, remoteRenderer, videoCapturer, videoCapturerSurfaceTextureHelper); + }); Button hangupButton = (Button) findViewById(R.id.hangup_button); - hangupButton.setOnClickListener((view) -> { callClient.hangup(); }); + hangupButton.setOnClickListener((view) -> { hangup(); }); } @Override @@ -54,18 +68,23 @@ public class MainActivity extends Activity { new GlRectDrawer()); remoteRenderer.init(eglBase.getEglBaseContext(), null /* rendererEvents */, EglBase.CONFIG_PLAIN, new GlRectDrawer()); + + videoCapturerSurfaceTextureHelper = + SurfaceTextureHelper.create("VideoCapturerThread", eglBase.getEglBaseContext()); } @Override protected void onStop() { - callClient.hangup(); + hangup(); localRenderer.release(); remoteRenderer.release(); + videoCapturerSurfaceTextureHelper.dispose(); eglBase.release(); localRenderer = null; remoteRenderer = null; + videoCapturerSurfaceTextureHelper = null; eglBase = null; super.onStop(); @@ -78,4 +97,24 @@ public class MainActivity extends Activity { super.onDestroy(); } + + private void hangup() { + if (videoCapturer != null) { + try { + videoCapturer.stopCapture(); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + videoCapturer.dispose(); + videoCapturer = null; + } + callClient.hangup(); + } + + private static VideoCapturer createVideoCapturer(Context context) { + CameraEnumerator enumerator = Camera2Enumerator.isSupported(context) + ? new Camera2Enumerator(context) + : new Camera1Enumerator(); + return enumerator.createCapturer(enumerator.getDeviceNames()[0], null /* eventsHandler */); + } } diff --git a/examples/androidnativeapi/jni/androidcallclient.cc b/examples/androidnativeapi/jni/androidcallclient.cc index 657bce2df6..4da20b995a 100644 --- a/examples/androidnativeapi/jni/androidcallclient.cc +++ b/examples/androidnativeapi/jni/androidcallclient.cc @@ -20,7 +20,6 @@ #include "media/engine/internalencoderfactory.h" #include "media/engine/webrtcmediaengine.h" #include "modules/audio_processing/include/audio_processing.h" -#include "pc/test/fakeperiodicvideocapturer.h" #include "rtc_base/ptr_util.h" #include "sdk/android/native_api/jni/java_types.h" #include "sdk/android/native_api/video/wrapper.h" @@ -97,16 +96,8 @@ void AndroidCallClient::Call(JNIEnv* env, local_sink_ = webrtc::JavaToNativeVideoSink(env, local_sink.obj()); remote_sink_ = webrtc::JavaToNativeVideoSink(env, remote_sink.obj()); - // The fake video source wants to be created on the same thread as it is - // destroyed. It is destroyed on the signaling thread so we have to invoke - // here. - // TODO(sakal): Get picture from camera? - video_source_ = pcf_->CreateVideoSource( - signaling_thread_ - ->Invoke>( - RTC_FROM_HERE, [&] { - return rtc::MakeUnique(); - })); + video_source_ = webrtc::CreateJavaVideoSource(env, signaling_thread_.get(), + false /* is_screencast */); CreatePeerConnection(); Connect(); @@ -138,6 +129,15 @@ void AndroidCallClient::Delete(JNIEnv* env, delete this; } +webrtc::ScopedJavaLocalRef +AndroidCallClient::GetJavaVideoCapturerObserver( + JNIEnv* env, + const webrtc::JavaRef& cls) { + RTC_DCHECK_RUN_ON(&thread_checker_); + + return video_source_->GetJavaVideoCapturerObserver(env); +} + void AndroidCallClient::CreatePeerConnectionFactory() { network_thread_ = rtc::Thread::CreateWithSocketServer(); network_thread_->SetName("network_thread", nullptr); @@ -277,10 +277,10 @@ void SetLocalSessionDescriptionObserver::OnFailure(const std::string& error) { RTC_LOG(LS_INFO) << "Set local description failure: " << error; } -} // namespace webrtc_examples - static jlong JNI_CallClient_CreateClient( JNIEnv* env, const webrtc::JavaParamRef& cls) { return webrtc::NativeToJavaPointer(new webrtc_examples::AndroidCallClient()); } + +} // namespace webrtc_examples diff --git a/examples/androidnativeapi/jni/androidcallclient.h b/examples/androidnativeapi/jni/androidcallclient.h index 2815b9d95f..a0507e3f7f 100644 --- a/examples/androidnativeapi/jni/androidcallclient.h +++ b/examples/androidnativeapi/jni/androidcallclient.h @@ -21,6 +21,7 @@ #include "rtc_base/scoped_ref_ptr.h" #include "rtc_base/thread_checker.h" #include "sdk/android/native_api/jni/scoped_java_ref.h" +#include "sdk/android/native_api/video/videosource.h" namespace webrtc_examples { @@ -36,6 +37,10 @@ class AndroidCallClient { // A helper method for Java code to delete this object. Calls delete this. void Delete(JNIEnv* env, const webrtc::JavaRef& cls); + webrtc::ScopedJavaLocalRef GetJavaVideoCapturerObserver( + JNIEnv* env, + const webrtc::JavaRef& cls); + private: class PCObserver; @@ -60,7 +65,7 @@ class AndroidCallClient { RTC_GUARDED_BY(thread_checker_); std::unique_ptr> remote_sink_ RTC_GUARDED_BY(thread_checker_); - rtc::scoped_refptr video_source_ + rtc::scoped_refptr video_source_ RTC_GUARDED_BY(thread_checker_); rtc::CriticalSection pc_mutex_;