diff options
Diffstat (limited to 'third_party/libwebrtc/examples/androidnativeapi')
11 files changed, 758 insertions, 0 deletions
diff --git a/third_party/libwebrtc/examples/androidnativeapi/AndroidManifest.xml b/third_party/libwebrtc/examples/androidnativeapi/AndroidManifest.xml new file mode 100644 index 0000000000..27c7d9dd35 --- /dev/null +++ b/third_party/libwebrtc/examples/androidnativeapi/AndroidManifest.xml @@ -0,0 +1,23 @@ +<?xml version="1.0" encoding="utf-8"?> +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="org.webrtc.examples.androidnativeapi"> + + + <uses-permission android:name="android.permission.INTERNET" /> + <uses-permission android:name="android.permission.CAMERA" /> + + <application + android:allowBackup="true" + android:label="@string/app_name" + android:supportsRtl="true"> + <activity android:name=".MainActivity" + android:exported="true"> + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + + <category android:name="android.intent.category.LAUNCHER" /> + </intent-filter> + </activity> + </application> + +</manifest> diff --git a/third_party/libwebrtc/examples/androidnativeapi/BUILD.gn b/third_party/libwebrtc/examples/androidnativeapi/BUILD.gn new file mode 100644 index 0000000000..e4c48a2b36 --- /dev/null +++ b/third_party/libwebrtc/examples/androidnativeapi/BUILD.gn @@ -0,0 +1,80 @@ +import("//webrtc.gni") + +if (is_android) { + rtc_android_apk("androidnativeapi") { + testonly = true + apk_name = "androidnativeapi" + android_manifest = "AndroidManifest.xml" + min_sdk_version = 21 + target_sdk_version = 31 + + sources = [ + "java/org/webrtc/examples/androidnativeapi/CallClient.java", + "java/org/webrtc/examples/androidnativeapi/MainActivity.java", + ] + + deps = [ + ":resources", + "//modules/audio_device:audio_device_java", + "//rtc_base:base_java", + "//sdk/android:camera_java", + "//sdk/android:surfaceviewrenderer_java", + "//sdk/android:video_api_java", + "//sdk/android:video_java", + "//third_party/androidx:androidx_annotation_annotation_java", + ] + + shared_libraries = [ ":examples_androidnativeapi_jni" ] + } + + generate_jni("generated_jni") { + testonly = true + sources = [ "java/org/webrtc/examples/androidnativeapi/CallClient.java" ] + namespace = "webrtc_examples" + jni_generator_include = "//sdk/android/src/jni/jni_generator_helper.h" + } + + rtc_shared_library("examples_androidnativeapi_jni") { + testonly = true + sources = [ + "jni/android_call_client.cc", + "jni/android_call_client.h", + "jni/onload.cc", + ] + + suppressed_configs += [ "//build/config/android:hide_all_but_jni_onload" ] + configs += [ "//build/config/android:hide_all_but_jni" ] + + deps = [ + ":generated_jni", + "../../api:scoped_refptr", + "../../api:sequence_checker", + "../../rtc_base:ssl", + "../../rtc_base/synchronization:mutex", + "//api:libjingle_peerconnection_api", + "//api/rtc_event_log:rtc_event_log_factory", + "//api/task_queue:default_task_queue_factory", + "//media:rtc_audio_video", + "//media:rtc_internal_video_codecs", + "//media:rtc_media_engine_defaults", + "//modules/utility", + "//pc:libjingle_peerconnection", + "//sdk/android:native_api_base", + "//sdk/android:native_api_jni", + "//sdk/android:native_api_video", + ] + } + + android_resources("resources") { + testonly = true + custom_package = "org.webrtc.examples.androidnativeapi" + sources = [ + "res/layout/activity_main.xml", + "res/values/strings.xml", + ] + + # Needed for Bazel converter. + resource_dirs = [ "res" ] + assert(resource_dirs != []) # Mark as used. + } +} diff --git a/third_party/libwebrtc/examples/androidnativeapi/DEPS b/third_party/libwebrtc/examples/androidnativeapi/DEPS new file mode 100644 index 0000000000..5dbfcf1bb8 --- /dev/null +++ b/third_party/libwebrtc/examples/androidnativeapi/DEPS @@ -0,0 +1,5 @@ +include_rules = [ + "+logging/rtc_event_log/rtc_event_log_factory.h", + "+modules/utility/include", + "+sdk/android/native_api", +] diff --git a/third_party/libwebrtc/examples/androidnativeapi/OWNERS b/third_party/libwebrtc/examples/androidnativeapi/OWNERS new file mode 100644 index 0000000000..cf092a316a --- /dev/null +++ b/third_party/libwebrtc/examples/androidnativeapi/OWNERS @@ -0,0 +1 @@ +xalep@webrtc.org diff --git a/third_party/libwebrtc/examples/androidnativeapi/java/org/webrtc/examples/androidnativeapi/CallClient.java b/third_party/libwebrtc/examples/androidnativeapi/java/org/webrtc/examples/androidnativeapi/CallClient.java new file mode 100644 index 0000000000..7369a1286d --- /dev/null +++ b/third_party/libwebrtc/examples/androidnativeapi/java/org/webrtc/examples/androidnativeapi/CallClient.java @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +package org.webrtc.examples.androidnativeapi; + +import android.content.Context; +import android.os.Handler; +import android.os.HandlerThread; +import org.webrtc.CapturerObserver; +import org.webrtc.SurfaceTextureHelper; +import org.webrtc.VideoCapturer; +import org.webrtc.VideoSink; + +public class CallClient { + private static final String TAG = "CallClient"; + private static final int CAPTURE_WIDTH = 640; + private static final int CAPTURE_HEIGHT = 480; + private static final int CAPTURE_FPS = 30; + + private final Context applicationContext; + private final HandlerThread thread; + private final Handler handler; + + private long nativeClient; + private SurfaceTextureHelper surfaceTextureHelper; + private VideoCapturer videoCapturer; + + public CallClient(Context applicationContext) { + this.applicationContext = applicationContext; + thread = new HandlerThread(TAG + "Thread"); + thread.start(); + handler = new Handler(thread.getLooper()); + handler.post(() -> { nativeClient = nativeCreateClient(); }); + } + + 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() { + handler.post(() -> { nativeHangup(nativeClient); }); + } + + public void close() { + handler.post(() -> { + nativeDelete(nativeClient); + nativeClient = 0; + }); + thread.quitSafely(); + } + + private static native long nativeCreateClient(); + private static native void nativeCall( + long nativeAndroidCallClient, VideoSink localSink, VideoSink remoteSink); + private static native void nativeHangup(long nativeAndroidCallClient); + private static native void nativeDelete(long nativeAndroidCallClient); + private static native CapturerObserver nativeGetJavaVideoCapturerObserver( + long nativeAndroidCallClient); +} diff --git a/third_party/libwebrtc/examples/androidnativeapi/java/org/webrtc/examples/androidnativeapi/MainActivity.java b/third_party/libwebrtc/examples/androidnativeapi/java/org/webrtc/examples/androidnativeapi/MainActivity.java new file mode 100644 index 0000000000..72fc0a686d --- /dev/null +++ b/third_party/libwebrtc/examples/androidnativeapi/java/org/webrtc/examples/androidnativeapi/MainActivity.java @@ -0,0 +1,120 @@ +/* + * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +package org.webrtc.examples.androidnativeapi; + +import android.app.Activity; +import android.content.Context; +import android.os.Bundle; +import android.widget.Button; +import androidx.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) { + ContextUtils.initialize(getApplicationContext()); + + super.onCreate(savedInstance); + setContentView(R.layout.activity_main); + + System.loadLibrary("examples_androidnativeapi_jni"); + callClient = new CallClient(getApplicationContext()); + + Button callButton = (Button) findViewById(R.id.call_button); + 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) -> { hangup(); }); + } + + @Override + protected void onStart() { + super.onStart(); + + eglBase = EglBase.create(null /* sharedContext */, EglBase.CONFIG_PLAIN); + localRenderer = (SurfaceViewRenderer) findViewById(R.id.local_renderer); + remoteRenderer = (SurfaceViewRenderer) findViewById(R.id.remote_renderer); + + localRenderer.init(eglBase.getEglBaseContext(), null /* rendererEvents */, EglBase.CONFIG_PLAIN, + new GlRectDrawer()); + remoteRenderer.init(eglBase.getEglBaseContext(), null /* rendererEvents */, + EglBase.CONFIG_PLAIN, new GlRectDrawer()); + + videoCapturerSurfaceTextureHelper = + SurfaceTextureHelper.create("VideoCapturerThread", eglBase.getEglBaseContext()); + } + + @Override + protected void onStop() { + hangup(); + + localRenderer.release(); + remoteRenderer.release(); + videoCapturerSurfaceTextureHelper.dispose(); + eglBase.release(); + + localRenderer = null; + remoteRenderer = null; + videoCapturerSurfaceTextureHelper = null; + eglBase = null; + + super.onStop(); + } + + @Override + protected void onDestroy() { + callClient.close(); + callClient = null; + + 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/third_party/libwebrtc/examples/androidnativeapi/jni/android_call_client.cc b/third_party/libwebrtc/examples/androidnativeapi/jni/android_call_client.cc new file mode 100644 index 0000000000..7da56e6e60 --- /dev/null +++ b/third_party/libwebrtc/examples/androidnativeapi/jni/android_call_client.cc @@ -0,0 +1,294 @@ +/* + * Copyright 2018 The WebRTC Project Authors. All rights reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "examples/androidnativeapi/jni/android_call_client.h" + +#include <utility> + +#include <memory> + +#include "api/peer_connection_interface.h" +#include "api/rtc_event_log/rtc_event_log_factory.h" +#include "api/task_queue/default_task_queue_factory.h" +#include "examples/androidnativeapi/generated_jni/CallClient_jni.h" +#include "media/engine/internal_decoder_factory.h" +#include "media/engine/internal_encoder_factory.h" +#include "media/engine/webrtc_media_engine.h" +#include "media/engine/webrtc_media_engine_defaults.h" +#include "sdk/android/native_api/jni/java_types.h" +#include "sdk/android/native_api/video/wrapper.h" + +namespace webrtc_examples { + +class AndroidCallClient::PCObserver : public webrtc::PeerConnectionObserver { + public: + explicit PCObserver(AndroidCallClient* client); + + void OnSignalingChange( + webrtc::PeerConnectionInterface::SignalingState new_state) override; + void OnDataChannel( + rtc::scoped_refptr<webrtc::DataChannelInterface> data_channel) override; + void OnRenegotiationNeeded() override; + void OnIceConnectionChange( + webrtc::PeerConnectionInterface::IceConnectionState new_state) override; + void OnIceGatheringChange( + webrtc::PeerConnectionInterface::IceGatheringState new_state) override; + void OnIceCandidate(const webrtc::IceCandidateInterface* candidate) override; + + private: + AndroidCallClient* const client_; +}; + +namespace { + +class CreateOfferObserver : public webrtc::CreateSessionDescriptionObserver { + public: + explicit CreateOfferObserver( + rtc::scoped_refptr<webrtc::PeerConnectionInterface> pc); + + void OnSuccess(webrtc::SessionDescriptionInterface* desc) override; + void OnFailure(webrtc::RTCError error) override; + + private: + const rtc::scoped_refptr<webrtc::PeerConnectionInterface> pc_; +}; + +class SetRemoteSessionDescriptionObserver + : public webrtc::SetRemoteDescriptionObserverInterface { + public: + void OnSetRemoteDescriptionComplete(webrtc::RTCError error) override; +}; + +class SetLocalSessionDescriptionObserver + : public webrtc::SetSessionDescriptionObserver { + public: + void OnSuccess() override; + void OnFailure(webrtc::RTCError error) override; +}; + +} // namespace + +AndroidCallClient::AndroidCallClient() + : call_started_(false), pc_observer_(std::make_unique<PCObserver>(this)) { + thread_checker_.Detach(); + CreatePeerConnectionFactory(); +} + +AndroidCallClient::~AndroidCallClient() = default; + +void AndroidCallClient::Call(JNIEnv* env, + const webrtc::JavaRef<jobject>& local_sink, + const webrtc::JavaRef<jobject>& remote_sink) { + RTC_DCHECK_RUN_ON(&thread_checker_); + + webrtc::MutexLock lock(&pc_mutex_); + if (call_started_) { + RTC_LOG(LS_WARNING) << "Call already started."; + return; + } + call_started_ = true; + + local_sink_ = webrtc::JavaToNativeVideoSink(env, local_sink.obj()); + remote_sink_ = webrtc::JavaToNativeVideoSink(env, remote_sink.obj()); + + video_source_ = webrtc::CreateJavaVideoSource(env, signaling_thread_.get(), + /* is_screencast= */ false, + /* align_timestamps= */ true); + + CreatePeerConnection(); + Connect(); +} + +void AndroidCallClient::Hangup(JNIEnv* env) { + RTC_DCHECK_RUN_ON(&thread_checker_); + + call_started_ = false; + + { + webrtc::MutexLock lock(&pc_mutex_); + if (pc_ != nullptr) { + pc_->Close(); + pc_ = nullptr; + } + } + + local_sink_ = nullptr; + remote_sink_ = nullptr; + video_source_ = nullptr; +} + +void AndroidCallClient::Delete(JNIEnv* env) { + RTC_DCHECK_RUN_ON(&thread_checker_); + + delete this; +} + +webrtc::ScopedJavaLocalRef<jobject> +AndroidCallClient::GetJavaVideoCapturerObserver(JNIEnv* env) { + 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); + RTC_CHECK(network_thread_->Start()) << "Failed to start thread"; + + worker_thread_ = rtc::Thread::Create(); + worker_thread_->SetName("worker_thread", nullptr); + RTC_CHECK(worker_thread_->Start()) << "Failed to start thread"; + + signaling_thread_ = rtc::Thread::Create(); + signaling_thread_->SetName("signaling_thread", nullptr); + RTC_CHECK(signaling_thread_->Start()) << "Failed to start thread"; + + webrtc::PeerConnectionFactoryDependencies pcf_deps; + pcf_deps.network_thread = network_thread_.get(); + pcf_deps.worker_thread = worker_thread_.get(); + pcf_deps.signaling_thread = signaling_thread_.get(); + pcf_deps.task_queue_factory = webrtc::CreateDefaultTaskQueueFactory(); + pcf_deps.call_factory = webrtc::CreateCallFactory(); + pcf_deps.event_log_factory = std::make_unique<webrtc::RtcEventLogFactory>( + pcf_deps.task_queue_factory.get()); + + cricket::MediaEngineDependencies media_deps; + media_deps.task_queue_factory = pcf_deps.task_queue_factory.get(); + media_deps.video_encoder_factory = + std::make_unique<webrtc::InternalEncoderFactory>(); + media_deps.video_decoder_factory = + std::make_unique<webrtc::InternalDecoderFactory>(); + webrtc::SetMediaEngineDefaults(&media_deps); + pcf_deps.media_engine = cricket::CreateMediaEngine(std::move(media_deps)); + RTC_LOG(LS_INFO) << "Media engine created: " << pcf_deps.media_engine.get(); + + pcf_ = CreateModularPeerConnectionFactory(std::move(pcf_deps)); + RTC_LOG(LS_INFO) << "PeerConnectionFactory created: " << pcf_.get(); +} + +void AndroidCallClient::CreatePeerConnection() { + webrtc::MutexLock lock(&pc_mutex_); + webrtc::PeerConnectionInterface::RTCConfiguration config; + config.sdp_semantics = webrtc::SdpSemantics::kUnifiedPlan; + // Encryption has to be disabled for loopback to work. + webrtc::PeerConnectionFactoryInterface::Options options; + options.disable_encryption = true; + pcf_->SetOptions(options); + webrtc::PeerConnectionDependencies deps(pc_observer_.get()); + pc_ = pcf_->CreatePeerConnectionOrError(config, std::move(deps)).MoveValue(); + + RTC_LOG(LS_INFO) << "PeerConnection created: " << pc_.get(); + + rtc::scoped_refptr<webrtc::VideoTrackInterface> local_video_track( + pcf_->CreateVideoTrack("video", video_source_.get())); + local_video_track->AddOrUpdateSink(local_sink_.get(), rtc::VideoSinkWants()); + pc_->AddTransceiver(local_video_track); + RTC_LOG(LS_INFO) << "Local video sink set up: " << local_video_track.get(); + + for (const rtc::scoped_refptr<webrtc::RtpTransceiverInterface>& tranceiver : + pc_->GetTransceivers()) { + rtc::scoped_refptr<webrtc::MediaStreamTrackInterface> track = + tranceiver->receiver()->track(); + if (track && + track->kind() == webrtc::MediaStreamTrackInterface::kVideoKind) { + static_cast<webrtc::VideoTrackInterface*>(track.get()) + ->AddOrUpdateSink(remote_sink_.get(), rtc::VideoSinkWants()); + RTC_LOG(LS_INFO) << "Remote video sink set up: " << track.get(); + break; + } + } +} + +void AndroidCallClient::Connect() { + webrtc::MutexLock lock(&pc_mutex_); + pc_->CreateOffer(rtc::make_ref_counted<CreateOfferObserver>(pc_).get(), + webrtc::PeerConnectionInterface::RTCOfferAnswerOptions()); +} + +AndroidCallClient::PCObserver::PCObserver(AndroidCallClient* client) + : client_(client) {} + +void AndroidCallClient::PCObserver::OnSignalingChange( + webrtc::PeerConnectionInterface::SignalingState new_state) { + RTC_LOG(LS_INFO) << "OnSignalingChange: " << new_state; +} + +void AndroidCallClient::PCObserver::OnDataChannel( + rtc::scoped_refptr<webrtc::DataChannelInterface> data_channel) { + RTC_LOG(LS_INFO) << "OnDataChannel"; +} + +void AndroidCallClient::PCObserver::OnRenegotiationNeeded() { + RTC_LOG(LS_INFO) << "OnRenegotiationNeeded"; +} + +void AndroidCallClient::PCObserver::OnIceConnectionChange( + webrtc::PeerConnectionInterface::IceConnectionState new_state) { + RTC_LOG(LS_INFO) << "OnIceConnectionChange: " << new_state; +} + +void AndroidCallClient::PCObserver::OnIceGatheringChange( + webrtc::PeerConnectionInterface::IceGatheringState new_state) { + RTC_LOG(LS_INFO) << "OnIceGatheringChange: " << new_state; +} + +void AndroidCallClient::PCObserver::OnIceCandidate( + const webrtc::IceCandidateInterface* candidate) { + RTC_LOG(LS_INFO) << "OnIceCandidate: " << candidate->server_url(); + webrtc::MutexLock lock(&client_->pc_mutex_); + RTC_DCHECK(client_->pc_ != nullptr); + client_->pc_->AddIceCandidate(candidate); +} + +CreateOfferObserver::CreateOfferObserver( + rtc::scoped_refptr<webrtc::PeerConnectionInterface> pc) + : pc_(pc) {} + +void CreateOfferObserver::OnSuccess(webrtc::SessionDescriptionInterface* desc) { + std::string sdp; + desc->ToString(&sdp); + RTC_LOG(LS_INFO) << "Created offer: " << sdp; + + // Ownership of desc was transferred to us, now we transfer it forward. + pc_->SetLocalDescription( + rtc::make_ref_counted<SetLocalSessionDescriptionObserver>().get(), desc); + + // Generate a fake answer. + std::unique_ptr<webrtc::SessionDescriptionInterface> answer( + webrtc::CreateSessionDescription(webrtc::SdpType::kAnswer, sdp)); + pc_->SetRemoteDescription( + std::move(answer), + rtc::make_ref_counted<SetRemoteSessionDescriptionObserver>()); +} + +void CreateOfferObserver::OnFailure(webrtc::RTCError error) { + RTC_LOG(LS_INFO) << "Failed to create offer: " << ToString(error.type()) + << ": " << error.message(); +} + +void SetRemoteSessionDescriptionObserver::OnSetRemoteDescriptionComplete( + webrtc::RTCError error) { + RTC_LOG(LS_INFO) << "Set remote description: " << error.message(); +} + +void SetLocalSessionDescriptionObserver::OnSuccess() { + RTC_LOG(LS_INFO) << "Set local description success!"; +} + +void SetLocalSessionDescriptionObserver::OnFailure(webrtc::RTCError error) { + RTC_LOG(LS_INFO) << "Set local description failure: " + << ToString(error.type()) << ": " << error.message(); +} + +static jlong JNI_CallClient_CreateClient(JNIEnv* env) { + return webrtc::NativeToJavaPointer(new webrtc_examples::AndroidCallClient()); +} + +} // namespace webrtc_examples diff --git a/third_party/libwebrtc/examples/androidnativeapi/jni/android_call_client.h b/third_party/libwebrtc/examples/androidnativeapi/jni/android_call_client.h new file mode 100644 index 0000000000..c9153d09bd --- /dev/null +++ b/third_party/libwebrtc/examples/androidnativeapi/jni/android_call_client.h @@ -0,0 +1,76 @@ +/* + * Copyright 2018 The WebRTC Project Authors. All rights reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef EXAMPLES_ANDROIDNATIVEAPI_JNI_ANDROID_CALL_CLIENT_H_ +#define EXAMPLES_ANDROIDNATIVEAPI_JNI_ANDROID_CALL_CLIENT_H_ + +#include <jni.h> + +#include <memory> +#include <string> + +#include "api/peer_connection_interface.h" +#include "api/scoped_refptr.h" +#include "api/sequence_checker.h" +#include "rtc_base/synchronization/mutex.h" +#include "sdk/android/native_api/jni/scoped_java_ref.h" +#include "sdk/android/native_api/video/video_source.h" + +namespace webrtc_examples { + +class AndroidCallClient { + public: + AndroidCallClient(); + ~AndroidCallClient(); + + void Call(JNIEnv* env, + const webrtc::JavaRef<jobject>& local_sink, + const webrtc::JavaRef<jobject>& remote_sink); + void Hangup(JNIEnv* env); + // A helper method for Java code to delete this object. Calls delete this. + void Delete(JNIEnv* env); + + webrtc::ScopedJavaLocalRef<jobject> GetJavaVideoCapturerObserver(JNIEnv* env); + + private: + class PCObserver; + + void CreatePeerConnectionFactory() RTC_RUN_ON(thread_checker_); + void CreatePeerConnection() RTC_RUN_ON(thread_checker_); + void Connect() RTC_RUN_ON(thread_checker_); + + webrtc::SequenceChecker thread_checker_; + + bool call_started_ RTC_GUARDED_BY(thread_checker_); + + const std::unique_ptr<PCObserver> pc_observer_; + + rtc::scoped_refptr<webrtc::PeerConnectionFactoryInterface> pcf_ + RTC_GUARDED_BY(thread_checker_); + std::unique_ptr<rtc::Thread> network_thread_ RTC_GUARDED_BY(thread_checker_); + std::unique_ptr<rtc::Thread> worker_thread_ RTC_GUARDED_BY(thread_checker_); + std::unique_ptr<rtc::Thread> signaling_thread_ + RTC_GUARDED_BY(thread_checker_); + + std::unique_ptr<rtc::VideoSinkInterface<webrtc::VideoFrame>> local_sink_ + RTC_GUARDED_BY(thread_checker_); + std::unique_ptr<rtc::VideoSinkInterface<webrtc::VideoFrame>> remote_sink_ + RTC_GUARDED_BY(thread_checker_); + rtc::scoped_refptr<webrtc::JavaVideoTrackSourceInterface> video_source_ + RTC_GUARDED_BY(thread_checker_); + + webrtc::Mutex pc_mutex_; + rtc::scoped_refptr<webrtc::PeerConnectionInterface> pc_ + RTC_GUARDED_BY(pc_mutex_); +}; + +} // namespace webrtc_examples + +#endif // EXAMPLES_ANDROIDNATIVEAPI_JNI_ANDROID_CALL_CLIENT_H_ diff --git a/third_party/libwebrtc/examples/androidnativeapi/jni/onload.cc b/third_party/libwebrtc/examples/androidnativeapi/jni/onload.cc new file mode 100644 index 0000000000..6ea5275d2a --- /dev/null +++ b/third_party/libwebrtc/examples/androidnativeapi/jni/onload.cc @@ -0,0 +1,30 @@ +/* + * Copyright 2018 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include <jni.h> + +#include "modules/utility/include/jvm_android.h" +#include "rtc_base/ssl_adapter.h" +#include "sdk/android/native_api/base/init.h" + +namespace webrtc_examples { + +extern "C" jint JNIEXPORT JNICALL JNI_OnLoad(JavaVM* jvm, void* reserved) { + webrtc::InitAndroid(jvm); + webrtc::JVM::Initialize(jvm); + RTC_CHECK(rtc::InitializeSSL()) << "Failed to InitializeSSL()"; + return JNI_VERSION_1_6; +} + +extern "C" void JNIEXPORT JNICALL JNI_OnUnLoad(JavaVM* jvm, void* reserved) { + RTC_CHECK(rtc::CleanupSSL()) << "Failed to CleanupSSL()"; +} + +} // namespace webrtc_examples diff --git a/third_party/libwebrtc/examples/androidnativeapi/res/layout/activity_main.xml b/third_party/libwebrtc/examples/androidnativeapi/res/layout/activity_main.xml new file mode 100644 index 0000000000..ac8037320f --- /dev/null +++ b/third_party/libwebrtc/examples/androidnativeapi/res/layout/activity_main.xml @@ -0,0 +1,52 @@ +<?xml version="1.0" encoding="utf-8"?> +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto" + xmlns:tools="http://schemas.android.com/tools" + android:orientation="vertical" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:padding="8dp" + tools:context="org.webrtc.examples.androidnativeapi.MainActivity"> + + <org.webrtc.SurfaceViewRenderer + android:id="@+id/local_renderer" + android:layout_width="match_parent" + android:layout_height="0dp" + android:layout_weight="1" + android:layout_margin="8dp"/> + + <org.webrtc.SurfaceViewRenderer + android:id="@+id/remote_renderer" + android:layout_width="match_parent" + android:layout_height="0dp" + android:layout_weight="1" + android:layout_margin="8dp"/> + + + <LinearLayout + android:orientation="horizontal" + android:layout_width="match_parent" + android:layout_height="48dp" + style="?android:attr/buttonBarStyle"> + + <Button + android:id="@+id/call_button" + android:text="@string/call_button" + style="?android:attr/buttonBarButtonStyle" + android:layout_width="0dp" + android:layout_height="48dp" + android:layout_weight="1" + android:layout_margin="8dp"/> + + <Button + android:id="@+id/hangup_button" + android:text="@string/hangup_button" + style="?android:attr/buttonBarButtonStyle" + android:layout_width="0dp" + android:layout_height="48dp" + android:layout_weight="1" + android:layout_margin="8dp"/> + + </LinearLayout> + +</LinearLayout> diff --git a/third_party/libwebrtc/examples/androidnativeapi/res/values/strings.xml b/third_party/libwebrtc/examples/androidnativeapi/res/values/strings.xml new file mode 100644 index 0000000000..a00920c92b --- /dev/null +++ b/third_party/libwebrtc/examples/androidnativeapi/res/values/strings.xml @@ -0,0 +1,5 @@ +<resources> + <string name="app_name">androidnativeapi</string> + <string name="call_button">Call</string> + <string name="hangup_button">Hangup</string> +</resources> |