diff --git a/webrtc/sdk/android/BUILD.gn b/webrtc/sdk/android/BUILD.gn index 9332a15d5b..07fc616017 100644 --- a/webrtc/sdk/android/BUILD.gn +++ b/webrtc/sdk/android/BUILD.gn @@ -22,30 +22,77 @@ config("libjingle_peerconnection_jni_warnings_config") { } } -rtc_static_library("libjingle_peerconnection_jni") { +rtc_source_set("base_jni") { sources = [ - "src/jni/androidhistogram_jni.cc", "src/jni/androidmediacodeccommon.h", - "src/jni/androidmediadecoder_jni.cc", - "src/jni/androidmediadecoder_jni.h", - "src/jni/androidmediaencoder_jni.cc", - "src/jni/androidmediaencoder_jni.h", - "src/jni/androidnetworkmonitor_jni.cc", - "src/jni/androidnetworkmonitor_jni.h", - "src/jni/androidvideotracksource.cc", - "src/jni/androidvideotracksource.h", - "src/jni/androidvideotracksource_jni.cc", + "src/jni/audio_jni.h", "src/jni/classreferenceholder.cc", "src/jni/classreferenceholder.h", "src/jni/jni_helpers.cc", "src/jni/jni_helpers.h", + "src/jni/media_jni.h", + "src/jni/ownedfactoryandthreads.cc", + "src/jni/ownedfactoryandthreads.h", + "src/jni/video_jni.h", + ] + + deps = [ + "//webrtc/api:libjingle_peerconnection_api", + "//webrtc/base:rtc_base", + "//webrtc/base:rtc_base_approved", + ] + + if (is_clang) { + # Suppress warnings from the Chromium Clang plugin (bugs.webrtc.org/163). + suppressed_configs += [ + "//build/config/clang:extra_warnings", + "//build/config/clang:find_bad_constructs", + ] + } +} + +rtc_static_library("audio_jni") { + sources = [ + "src/jni/audio_jni.cc", + ] + + deps = [ + ":base_jni", + "//webrtc/api/audio_codecs:builtin_audio_decoder_factory", + "//webrtc/api/audio_codecs:builtin_audio_encoder_factory", + "//webrtc/voice_engine:voice_engine", + ] +} + +rtc_static_library("null_audio_jni") { + sources = [ + "src/jni/null_audio_jni.cc", + ] + + deps = [ + ":base_jni", + "//webrtc/api:libjingle_peerconnection_api", + "//webrtc/base:rtc_base", + "//webrtc/base:rtc_base_approved", + ] +} + +rtc_static_library("video_jni") { + sources = [ + "src/jni/androidhistogram_jni.cc", + "src/jni/androidmediadecoder_jni.cc", + "src/jni/androidmediadecoder_jni.h", + "src/jni/androidmediaencoder_jni.cc", + "src/jni/androidmediaencoder_jni.h", + "src/jni/androidvideotracksource.cc", + "src/jni/androidvideotracksource.h", + "src/jni/androidvideotracksource_jni.cc", "src/jni/native_handle_impl.cc", "src/jni/native_handle_impl.h", - "src/jni/peerconnection_jni.cc", - "src/jni/rtcstatscollectorcallbackwrapper.cc", - "src/jni/rtcstatscollectorcallbackwrapper.h", "src/jni/surfacetexturehelper_jni.cc", "src/jni/surfacetexturehelper_jni.h", + "src/jni/video_jni.cc", + "src/jni/video_renderer_jni.cc", "src/jni/wrapped_native_i420_buffer.cc", "src/jni/wrapped_native_i420_buffer.h", ] @@ -71,22 +118,22 @@ rtc_static_library("libjingle_peerconnection_jni") { } deps = [ - "../..:webrtc_common", - "../../api:video_frame_api", - "../../api/video_codecs:video_codecs_api", - "../../base:rtc_base", - "../../base:rtc_base_approved", - "../../base:rtc_task_queue", - "../../base:sequenced_task_checker", - "../../base:weak_ptr", - "../../common_video:common_video", - "../../media:rtc_media", - "../../media:rtc_media_base", - "../../modules/utility:utility", - "../../modules/video_coding:video_coding_utility", - "../../system_wrappers:system_wrappers", - "../../voice_engine:voice_engine", - "//webrtc/pc:libjingle_peerconnection", + ":base_jni", + "//webrtc:webrtc_common", + "//webrtc/api:libjingle_peerconnection_api", + "//webrtc/api:video_frame_api", + "//webrtc/api/video_codecs:video_codecs_api", + "//webrtc/base:rtc_base", + "//webrtc/base:rtc_base_approved", + "//webrtc/base:rtc_task_queue", + "//webrtc/base:sequenced_task_checker", + "//webrtc/base:weak_ptr", + "//webrtc/common_video:common_video", + "//webrtc/media:rtc_audio_video", + "//webrtc/media:rtc_media_base", + "//webrtc/modules/utility:utility", + "//webrtc/modules/video_coding:video_coding_utility", + "//webrtc/system_wrappers:system_wrappers", ] if (rtc_build_libyuv) { @@ -100,6 +147,124 @@ rtc_static_library("libjingle_peerconnection_jni") { } } +rtc_static_library("null_video_jni") { + sources = [ + "src/jni/null_video_jni.cc", + ] + + deps = [ + ":base_jni", + "//webrtc/base:rtc_base_approved", + ] + + if (is_clang) { + # Suppress warnings from the Chromium Clang plugin (bugs.webrtc.org/163). + suppressed_configs += [ + "//build/config/clang:extra_warnings", + "//build/config/clang:find_bad_constructs", + ] + } +} + +rtc_static_library("media_jni") { + sources = [ + "src/jni/media_jni.cc", + ] + + deps = [ + ":base_jni", + "//webrtc/api:libjingle_peerconnection_api", + "//webrtc/api/audio_codecs:audio_codecs_api", + "//webrtc/base:rtc_base_approved", + "//webrtc/media:rtc_audio_video", + ] + + if (is_clang) { + # Suppress warnings from the Chromium Clang plugin (bugs.webrtc.org/163). + suppressed_configs += [ + "//build/config/clang:extra_warnings", + "//build/config/clang:find_bad_constructs", + ] + } +} + +rtc_static_library("null_media_jni") { + sources = [ + "src/jni/null_media_jni.cc", + ] + + deps = [ + ":base_jni", + "//webrtc/api:libjingle_peerconnection_api", + "//webrtc/base:rtc_base", + "//webrtc/base:rtc_base_approved", + "//webrtc/call:call_interfaces", + "//webrtc/logging:rtc_event_log_api", + ] + + if (is_clang) { + # Suppress warnings from the Chromium Clang plugin (bugs.webrtc.org/163). + suppressed_configs += [ + "//build/config/clang:extra_warnings", + "//build/config/clang:find_bad_constructs", + ] + } +} + +rtc_static_library("peerconnection_jni") { + sources = [ + "src/jni/androidnetworkmonitor_jni.cc", + "src/jni/androidnetworkmonitor_jni.h", + "src/jni/peerconnection_jni.cc", + "src/jni/rtcstatscollectorcallbackwrapper.cc", + "src/jni/rtcstatscollectorcallbackwrapper.h", + ] + + configs += [ ":libjingle_peerconnection_jni_warnings_config" ] + + if (is_clang) { + # Suppress warnings from the Chromium Clang plugin (bugs.webrtc.org/163). + suppressed_configs += [ + "//build/config/clang:extra_warnings", + "//build/config/clang:find_bad_constructs", + ] + } + + # TODO(jschuh): Bug 1348: fix this warning. + configs += [ "//build/config/compiler:no_size_t_to_int_warning" ] + + if (is_win) { + cflags += [ + "/wd4245", # conversion from "int" to "size_t", signed/unsigned mismatch. + "/wd4389", # signed/unsigned mismatch. + ] + } + + deps = [ + ":base_jni", + "../..:webrtc_common", + "//webrtc/base:rtc_base", + "//webrtc/base:rtc_base_approved", + "//webrtc/base:rtc_task_queue", + "//webrtc/media:rtc_data", + "//webrtc/media:rtc_media_base", + "//webrtc/modules/utility:utility", + "//webrtc/pc:peerconnection", + "//webrtc/system_wrappers:system_wrappers", + ] +} + +rtc_static_library("libjingle_peerconnection_jni") { + public_deps = [ + ":audio_jni", + ":base_jni", + ":media_jni", + ":peerconnection_jni", + ":video_jni", + "//webrtc/pc:create_pc_factory", + ] +} + rtc_static_library("libjingle_peerconnection_metrics_default_jni") { sources = [ "src/jni/androidmetrics_jni.cc", @@ -108,14 +273,44 @@ rtc_static_library("libjingle_peerconnection_metrics_default_jni") { configs += [ ":libjingle_peerconnection_jni_warnings_config" ] deps = [ - ":libjingle_peerconnection_jni", - "../../system_wrappers", - "//webrtc/pc:libjingle_peerconnection", + ":base_jni", + ":peerconnection_jni", + "//webrtc/pc:peerconnection", + "//webrtc/system_wrappers", "//webrtc/system_wrappers:field_trial_default", "//webrtc/system_wrappers:metrics_default", ] } +# The modular build targets can be used to build WebRTC with different +# functionalities. The users can choose either the real implemenation or the +# null implementation of the audio/video modules based on their requirments. +# +# For example, to build WebRTC with datachannel support only, we would need the +# the peerconnection and the null implementation of the audio, video and media +# module. +# rtc_shared_library("libjingle_peerconnection_datachannelonly_so") { +# sources = [ +# "src/jni/jni_onload.cc", +# ] +# +# suppressed_configs += [ "//build/config/android:hide_all_but_jni_onload" ] +# configs += [ "//build/config/android:hide_all_but_jni" ] +# +# deps = [ +# ":base_jni", +# ":libjingle_peerconnection_metrics_default_jni", +# ":null_audio_jni", +# ":null_media_jni", +# ":null_video_jni", +# ":peerconnection_jni", +# "//webrtc/base:rtc_base", +# "//webrtc/base:rtc_base_approved", +# "//webrtc/pc:peerconnection", +# ] +# output_extension = "so" +# } + rtc_shared_library("libjingle_peerconnection_so") { sources = [ "src/jni/jni_onload.cc", @@ -127,7 +322,7 @@ rtc_shared_library("libjingle_peerconnection_so") { deps = [ ":libjingle_peerconnection_jni", ":libjingle_peerconnection_metrics_default_jni", - "../../base:rtc_base", + "//webrtc/base:rtc_base", "//webrtc/pc:libjingle_peerconnection", ] output_extension = "so" diff --git a/webrtc/sdk/android/instrumentationtests/src/org/webrtc/PeerConnectionTest.java b/webrtc/sdk/android/instrumentationtests/src/org/webrtc/PeerConnectionTest.java index 30595a391e..af6f9884fb 100644 --- a/webrtc/sdk/android/instrumentationtests/src/org/webrtc/PeerConnectionTest.java +++ b/webrtc/sdk/android/instrumentationtests/src/org/webrtc/PeerConnectionTest.java @@ -805,6 +805,156 @@ public class PeerConnectionTest { System.gc(); } + @Test + @MediumTest + public void testDataChannelOnlySession() throws Exception { + // Allow loopback interfaces too since our Android devices often don't + // have those. + PeerConnectionFactory.Options options = new PeerConnectionFactory.Options(); + options.networkIgnoreMask = 0; + PeerConnectionFactory factory = new PeerConnectionFactory(options); + + MediaConstraints pcConstraints = new MediaConstraints(); + pcConstraints.mandatory.add(new MediaConstraints.KeyValuePair("DtlsSrtpKeyAgreement", "true")); + + LinkedList iceServers = new LinkedList(); + iceServers.add(new PeerConnection.IceServer("stun:stun.l.google.com:19302")); + iceServers.add( + new PeerConnection.IceServer("turn:fake.example.com", "fakeUsername", "fakePassword")); + ObserverExpectations offeringExpectations = new ObserverExpectations("PCTest:offerer"); + PeerConnection offeringPC = + factory.createPeerConnection(iceServers, pcConstraints, offeringExpectations); + assertNotNull(offeringPC); + + ObserverExpectations answeringExpectations = new ObserverExpectations("PCTest:answerer"); + PeerConnection answeringPC = + factory.createPeerConnection(iceServers, pcConstraints, answeringExpectations); + assertNotNull(answeringPC); + + offeringExpectations.expectRenegotiationNeeded(); + DataChannel offeringDC = offeringPC.createDataChannel("offeringDC", new DataChannel.Init()); + assertEquals("offeringDC", offeringDC.label()); + + offeringExpectations.setDataChannel(offeringDC); + SdpObserverLatch sdpLatch = new SdpObserverLatch(); + offeringPC.createOffer(sdpLatch, new MediaConstraints()); + assertTrue(sdpLatch.await()); + SessionDescription offerSdp = sdpLatch.getSdp(); + assertEquals(offerSdp.type, SessionDescription.Type.OFFER); + assertFalse(offerSdp.description.isEmpty()); + + sdpLatch = new SdpObserverLatch(); + answeringExpectations.expectSignalingChange(SignalingState.HAVE_REMOTE_OFFER); + // SCTP DataChannels are announced via OPEN messages over the established + // connection (not via SDP), so answeringExpectations can only register + // expecting the channel during ICE, below. + answeringPC.setRemoteDescription(sdpLatch, offerSdp); + assertEquals(PeerConnection.SignalingState.STABLE, offeringPC.signalingState()); + assertTrue(sdpLatch.await()); + assertNull(sdpLatch.getSdp()); + + sdpLatch = new SdpObserverLatch(); + answeringPC.createAnswer(sdpLatch, new MediaConstraints()); + assertTrue(sdpLatch.await()); + SessionDescription answerSdp = sdpLatch.getSdp(); + assertEquals(answerSdp.type, SessionDescription.Type.ANSWER); + assertFalse(answerSdp.description.isEmpty()); + + offeringExpectations.expectIceCandidates(2); + answeringExpectations.expectIceCandidates(2); + + offeringExpectations.expectIceGatheringChange(IceGatheringState.COMPLETE); + answeringExpectations.expectIceGatheringChange(IceGatheringState.COMPLETE); + + sdpLatch = new SdpObserverLatch(); + answeringExpectations.expectSignalingChange(SignalingState.STABLE); + answeringPC.setLocalDescription(sdpLatch, answerSdp); + assertTrue(sdpLatch.await()); + assertNull(sdpLatch.getSdp()); + + sdpLatch = new SdpObserverLatch(); + offeringExpectations.expectSignalingChange(SignalingState.HAVE_LOCAL_OFFER); + offeringPC.setLocalDescription(sdpLatch, offerSdp); + assertTrue(sdpLatch.await()); + assertNull(sdpLatch.getSdp()); + sdpLatch = new SdpObserverLatch(); + offeringExpectations.expectSignalingChange(SignalingState.STABLE); + + offeringExpectations.expectIceConnectionChange(IceConnectionState.CHECKING); + offeringExpectations.expectIceConnectionChange(IceConnectionState.CONNECTED); + // TODO(bemasc): uncomment once delivery of ICECompleted is reliable + // (https://code.google.com/p/webrtc/issues/detail?id=3021). + answeringExpectations.expectIceConnectionChange(IceConnectionState.CHECKING); + answeringExpectations.expectIceConnectionChange(IceConnectionState.CONNECTED); + + offeringPC.setRemoteDescription(sdpLatch, answerSdp); + assertTrue(sdpLatch.await()); + assertNull(sdpLatch.getSdp()); + + assertEquals(offeringPC.getLocalDescription().type, offerSdp.type); + assertEquals(offeringPC.getRemoteDescription().type, answerSdp.type); + assertEquals(answeringPC.getLocalDescription().type, answerSdp.type); + assertEquals(answeringPC.getRemoteDescription().type, offerSdp.type); + + offeringExpectations.expectStateChange(DataChannel.State.OPEN); + // See commentary about SCTP DataChannels above for why this is here. + answeringExpectations.expectDataChannel("offeringDC"); + answeringExpectations.expectStateChange(DataChannel.State.OPEN); + + // Wait for at least one ice candidate from the offering PC and forward them to the answering + // PC. + for (IceCandidate candidate : offeringExpectations.getAtLeastOneIceCandidate()) { + answeringPC.addIceCandidate(candidate); + } + + // Wait for at least one ice candidate from the answering PC and forward them to the offering + // PC. + for (IceCandidate candidate : answeringExpectations.getAtLeastOneIceCandidate()) { + offeringPC.addIceCandidate(candidate); + } + + assertTrue(offeringExpectations.waitForAllExpectationsToBeSatisfied(TIMEOUT_SECONDS)); + assertTrue(answeringExpectations.waitForAllExpectationsToBeSatisfied(TIMEOUT_SECONDS)); + + assertEquals(PeerConnection.SignalingState.STABLE, offeringPC.signalingState()); + assertEquals(PeerConnection.SignalingState.STABLE, answeringPC.signalingState()); + + // Test send & receive UTF-8 text. + answeringExpectations.expectMessage( + ByteBuffer.wrap("hello!".getBytes(Charset.forName("UTF-8"))), false); + DataChannel.Buffer buffer = + new DataChannel.Buffer(ByteBuffer.wrap("hello!".getBytes(Charset.forName("UTF-8"))), false); + assertTrue(offeringExpectations.dataChannel.send(buffer)); + assertTrue(answeringExpectations.waitForAllExpectationsToBeSatisfied(TIMEOUT_SECONDS)); + + // Construct this binary message two different ways to ensure no + // shortcuts are taken. + ByteBuffer expectedBinaryMessage = ByteBuffer.allocateDirect(5); + for (byte i = 1; i < 6; ++i) { + expectedBinaryMessage.put(i); + } + expectedBinaryMessage.flip(); + offeringExpectations.expectMessage(expectedBinaryMessage, true); + assertTrue(answeringExpectations.dataChannel.send( + new DataChannel.Buffer(ByteBuffer.wrap(new byte[] {1, 2, 3, 4, 5}), true))); + assertTrue(offeringExpectations.waitForAllExpectationsToBeSatisfied(TIMEOUT_SECONDS)); + + offeringExpectations.expectStateChange(DataChannel.State.CLOSING); + answeringExpectations.expectStateChange(DataChannel.State.CLOSING); + offeringExpectations.expectStateChange(DataChannel.State.CLOSED); + answeringExpectations.expectStateChange(DataChannel.State.CLOSED); + answeringExpectations.dataChannel.close(); + offeringExpectations.dataChannel.close(); + + // Free the Java-land objects and collect them. + shutdownPC(offeringPC, offeringExpectations); + offeringPC = null; + shutdownPC(answeringPC, answeringExpectations); + answeringPC = null; + factory.dispose(); + System.gc(); + } + // Flaky on Android. See webrtc:7761 @DisabledTest @Test diff --git a/webrtc/sdk/android/src/jni/DEPS b/webrtc/sdk/android/src/jni/DEPS index 108f71f4c2..9f982707b1 100644 --- a/webrtc/sdk/android/src/jni/DEPS +++ b/webrtc/sdk/android/src/jni/DEPS @@ -1,11 +1,16 @@ include_rules = [ "+third_party/libyuv", + "+webrtc/call/callfactoryinterface.h", "+webrtc/common_video/h264/h264_bitstream_parser.h", "+webrtc/common_video/include", "+webrtc/common_video/libyuv/include/webrtc_libyuv.h", + "+webrtc/logging/rtc_event_log/rtc_event_log_factory_interface.h", + "+webrtc/media/base", + "+webrtc/media/engine", "+webrtc/modules/utility/include/jvm_android.h", "+webrtc/modules/video_coding/utility/vp8_header_parser.h", "+webrtc/modules/video_coding/utility/vp9_uncompressed_header_parser.h", "+webrtc/pc", "+webrtc/system_wrappers/include", + "+webrtc/voice_engine/include/voe_base.h", ] diff --git a/webrtc/sdk/android/src/jni/audio_jni.cc b/webrtc/sdk/android/src/jni/audio_jni.cc new file mode 100644 index 0000000000..58ab73ec65 --- /dev/null +++ b/webrtc/sdk/android/src/jni/audio_jni.cc @@ -0,0 +1,26 @@ +/* + * Copyright 2017 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 "webrtc/sdk/android/src/jni/audio_jni.h" + +#include "webrtc/api/audio_codecs/builtin_audio_decoder_factory.h" +#include "webrtc/api/audio_codecs/builtin_audio_encoder_factory.h" + +namespace webrtc_jni { + +rtc::scoped_refptr CreateAudioDecoderFactory() { + return webrtc::CreateBuiltinAudioDecoderFactory(); +} + +rtc::scoped_refptr CreateAudioEncoderFactory() { + return webrtc::CreateBuiltinAudioEncoderFactory(); +} + +} // namespace webrtc_jni diff --git a/webrtc/sdk/android/src/jni/audio_jni.h b/webrtc/sdk/android/src/jni/audio_jni.h new file mode 100644 index 0000000000..3a0b0bd700 --- /dev/null +++ b/webrtc/sdk/android/src/jni/audio_jni.h @@ -0,0 +1,28 @@ +/* + * Copyright 2017 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 WEBRTC_SDK_ANDROID_SRC_JNI_AUDIO_JNI_H_ +#define WEBRTC_SDK_ANDROID_SRC_JNI_AUDIO_JNI_H_ + +// Adding 'nogncheck' to disable the gn include headers check. +// We don't want this target depend on audio related targets +#include "webrtc/api/audio_codecs/audio_decoder_factory.h" // nogncheck +#include "webrtc/api/audio_codecs/audio_encoder_factory.h" // nogncheck +#include "webrtc/base/scoped_ref_ptr.h" + +namespace webrtc_jni { + +rtc::scoped_refptr CreateAudioDecoderFactory(); + +rtc::scoped_refptr CreateAudioEncoderFactory(); + +} // namespace webrtc_jni + +#endif // WEBRTC_SDK_ANDROID_SRC_JNI_AUDIO_JNI_H_ diff --git a/webrtc/sdk/android/src/jni/media_jni.cc b/webrtc/sdk/android/src/jni/media_jni.cc new file mode 100644 index 0000000000..7fbc67490a --- /dev/null +++ b/webrtc/sdk/android/src/jni/media_jni.cc @@ -0,0 +1,35 @@ +/* + * Copyright 2017 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 "webrtc/sdk/android/src/jni/media_jni.h" + +#include "webrtc/api/audio_codecs/audio_decoder_factory.h" +#include "webrtc/api/audio_codecs/audio_encoder_factory.h" +#include "webrtc/media/engine/webrtcvideodecoderfactory.h" +#include "webrtc/media/engine/webrtcvideoencoderfactory.h" + +namespace webrtc_jni { + +rtc::scoped_refptr +CreateNativePeerConnectionFactory( + rtc::Thread* network_thread, + rtc::Thread* worker_thread, + rtc::Thread* signaling_thread, + webrtc::AudioDeviceModule* default_adm, + rtc::scoped_refptr audio_encoder_factory, + rtc::scoped_refptr audio_decoder_factory, + cricket::WebRtcVideoEncoderFactory* video_encoder_factory, + cricket::WebRtcVideoDecoderFactory* video_decoder_factory) { + return webrtc::CreatePeerConnectionFactory( + network_thread, worker_thread, signaling_thread, default_adm, + audio_encoder_factory, audio_decoder_factory, video_encoder_factory, + video_decoder_factory); +} + +} // namespace webrtc_jni diff --git a/webrtc/sdk/android/src/jni/media_jni.h b/webrtc/sdk/android/src/jni/media_jni.h new file mode 100644 index 0000000000..168b12544e --- /dev/null +++ b/webrtc/sdk/android/src/jni/media_jni.h @@ -0,0 +1,33 @@ +/* + * Copyright 2017 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 WEBRTC_SDK_ANDROID_SRC_JNI_MEDIA_JNI_H_ +#define WEBRTC_SDK_ANDROID_SRC_JNI_MEDIA_JNI_H_ + +#include "webrtc/api/peerconnectioninterface.h" +#include "webrtc/base/scoped_ref_ptr.h" +#include "webrtc/base/thread.h" + +namespace webrtc_jni { + +rtc::scoped_refptr +CreateNativePeerConnectionFactory( + rtc::Thread* network_thread, + rtc::Thread* worker_thread, + rtc::Thread* signaling_thread, + webrtc::AudioDeviceModule* default_adm, + rtc::scoped_refptr audio_encoder_factory, + rtc::scoped_refptr audio_decoder_factory, + cricket::WebRtcVideoEncoderFactory* video_encoder_factory, + cricket::WebRtcVideoDecoderFactory* video_decoder_factory); + +} // namespace webrtc_jni + +#endif // WEBRTC_SDK_ANDROID_SRC_JNI_MEDIA_JNI_H_ diff --git a/webrtc/sdk/android/src/jni/null_audio_jni.cc b/webrtc/sdk/android/src/jni/null_audio_jni.cc new file mode 100644 index 0000000000..8599b870fa --- /dev/null +++ b/webrtc/sdk/android/src/jni/null_audio_jni.cc @@ -0,0 +1,22 @@ +/* + * Copyright 2017 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 "webrtc/sdk/android/src/jni/audio_jni.h" + +namespace webrtc_jni { + +rtc::scoped_refptr CreateAudioDecoderFactory() { + return rtc::scoped_refptr(); +} + +rtc::scoped_refptr CreateAudioEncoderFactory() { + return rtc::scoped_refptr(); +} + +} // namespace webrtc_jni diff --git a/webrtc/sdk/android/src/jni/null_media_jni.cc b/webrtc/sdk/android/src/jni/null_media_jni.cc new file mode 100644 index 0000000000..b41f5c41b7 --- /dev/null +++ b/webrtc/sdk/android/src/jni/null_media_jni.cc @@ -0,0 +1,43 @@ +/* + * Copyright 2017 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 "webrtc/sdk/android/src/jni/media_jni.h" + +#include "webrtc/api/audio_codecs/audio_decoder_factory.h" // nogncheck +#include "webrtc/api/audio_codecs/audio_encoder_factory.h" // nogncheck +#include "webrtc/call/callfactoryinterface.h" +#include "webrtc/logging/rtc_event_log/rtc_event_log_factory_interface.h" +#include "webrtc/media/engine/webrtcvideodecoderfactory.h" // nogncheck +#include "webrtc/media/engine/webrtcvideoencoderfactory.h" // nogncheck + +namespace webrtc_jni { + +// This implementation is used for building WebRTC without audio and video +// support. +rtc::scoped_refptr +CreateNativePeerConnectionFactory( + rtc::Thread* network_thread, + rtc::Thread* worker_thread, + rtc::Thread* signaling_thread, + webrtc::AudioDeviceModule* default_adm, + rtc::scoped_refptr audio_encoder_factory, + rtc::scoped_refptr audio_decoder_factory, + cricket::WebRtcVideoEncoderFactory* video_encoder_factory, + cricket::WebRtcVideoDecoderFactory* video_decoder_factory) { + return CreateModularPeerConnectionFactory( + network_thread, worker_thread, signaling_thread, default_adm, + audio_encoder_factory, audio_decoder_factory, video_encoder_factory, + video_decoder_factory, nullptr /*audio_mixer*/, + std::unique_ptr(), + std::unique_ptr(), + std::unique_ptr()); +} + +} // namespace webrtc_jni diff --git a/webrtc/sdk/android/src/jni/null_video_jni.cc b/webrtc/sdk/android/src/jni/null_video_jni.cc new file mode 100644 index 0000000000..82394ff958 --- /dev/null +++ b/webrtc/sdk/android/src/jni/null_video_jni.cc @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2017 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 + +#include "webrtc/base/scoped_ref_ptr.h" +#include "webrtc/sdk/android/src/jni/classreferenceholder.h" + +namespace cricket { +class WebRtcVideoEncoderFactory; +class WebRtcVideoDecoderFactory; +} // namespace cricket + +namespace webrtc_jni { + +class MediaCodecVideoEncoderFactory; +class MediaCodecVideoDecoderFactory; +class SurfaceTextureHelper; + +cricket::WebRtcVideoEncoderFactory* CreateVideoEncoderFactory() { + return nullptr; +} + +cricket::WebRtcVideoDecoderFactory* CreateVideoDecoderFactory() { + return nullptr; +} + +jobject GetJavaSurfaceTextureHelper( + rtc::scoped_refptr surface_texture_helper) { + return nullptr; +} + +} // namespace webrtc_jni diff --git a/webrtc/sdk/android/src/jni/ownedfactoryandthreads.cc b/webrtc/sdk/android/src/jni/ownedfactoryandthreads.cc new file mode 100644 index 0000000000..7171852dec --- /dev/null +++ b/webrtc/sdk/android/src/jni/ownedfactoryandthreads.cc @@ -0,0 +1,64 @@ +/* + * Copyright 2017 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 "webrtc/sdk/android/src/jni/ownedfactoryandthreads.h" + +#include "webrtc/base/logging.h" +#include "webrtc/sdk/android/src/jni/classreferenceholder.h" +#include "webrtc/sdk/android/src/jni/jni_helpers.h" + +namespace webrtc_jni { + +PeerConnectionFactoryInterface* factoryFromJava(jlong j_p) { + return reinterpret_cast(j_p)->factory(); +} + +OwnedFactoryAndThreads::~OwnedFactoryAndThreads() { + CHECK_RELEASE(factory_); + if (network_monitor_factory_ != nullptr) { + rtc::NetworkMonitorFactory::ReleaseFactory(network_monitor_factory_); + } +} + +void OwnedFactoryAndThreads::JavaCallbackOnFactoryThreads() { + JNIEnv* jni = AttachCurrentThreadIfNeeded(); + ScopedLocalRefFrame local_ref_frame(jni); + jclass j_factory_class = FindClass(jni, "org/webrtc/PeerConnectionFactory"); + jmethodID m = nullptr; + if (network_thread_->IsCurrent()) { + LOG(LS_INFO) << "Network thread JavaCallback"; + m = GetStaticMethodID(jni, j_factory_class, "onNetworkThreadReady", "()V"); + } + if (worker_thread_->IsCurrent()) { + LOG(LS_INFO) << "Worker thread JavaCallback"; + m = GetStaticMethodID(jni, j_factory_class, "onWorkerThreadReady", "()V"); + } + if (signaling_thread_->IsCurrent()) { + LOG(LS_INFO) << "Signaling thread JavaCallback"; + m = GetStaticMethodID(jni, j_factory_class, "onSignalingThreadReady", + "()V"); + } + if (m != nullptr) { + jni->CallStaticVoidMethod(j_factory_class, m); + CHECK_EXCEPTION(jni) << "error during JavaCallback::CallStaticVoidMethod"; + } +} + +void OwnedFactoryAndThreads::InvokeJavaCallbacksOnFactoryThreads() { + LOG(LS_INFO) << "InvokeJavaCallbacksOnFactoryThreads."; + network_thread_->Invoke(RTC_FROM_HERE, + [this] { JavaCallbackOnFactoryThreads(); }); + worker_thread_->Invoke(RTC_FROM_HERE, + [this] { JavaCallbackOnFactoryThreads(); }); + signaling_thread_->Invoke(RTC_FROM_HERE, + [this] { JavaCallbackOnFactoryThreads(); }); +} + +} // namespace webrtc_jni diff --git a/webrtc/sdk/android/src/jni/ownedfactoryandthreads.h b/webrtc/sdk/android/src/jni/ownedfactoryandthreads.h new file mode 100644 index 0000000000..920cb939a0 --- /dev/null +++ b/webrtc/sdk/android/src/jni/ownedfactoryandthreads.h @@ -0,0 +1,80 @@ +/* + * Copyright 2017 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 WEBRTC_SDK_ANDROID_SRC_JNI_OWNEDFACTORYANDTHREADS_H_ +#define WEBRTC_SDK_ANDROID_SRC_JNI_OWNEDFACTORYANDTHREADS_H_ + +#include +#include +#include + +#include "webrtc/api/peerconnectioninterface.h" +#include "webrtc/base/thread.h" + +using cricket::WebRtcVideoDecoderFactory; +using cricket::WebRtcVideoEncoderFactory; +using rtc::Thread; +using webrtc::PeerConnectionFactoryInterface; + +namespace webrtc_jni { + +PeerConnectionFactoryInterface* factoryFromJava(jlong j_p); + +// Helper struct for working around the fact that CreatePeerConnectionFactory() +// comes in two flavors: either entirely automagical (constructing its own +// threads and deleting them on teardown, but no external codec factory support) +// or entirely manual (requires caller to delete threads after factory +// teardown). This struct takes ownership of its ctor's arguments to present a +// single thing for Java to hold and eventually free. +class OwnedFactoryAndThreads { + public: + OwnedFactoryAndThreads(std::unique_ptr network_thread, + std::unique_ptr worker_thread, + std::unique_ptr signaling_thread, + WebRtcVideoEncoderFactory* encoder_factory, + WebRtcVideoDecoderFactory* decoder_factory, + rtc::NetworkMonitorFactory* network_monitor_factory, + PeerConnectionFactoryInterface* factory) + : network_thread_(std::move(network_thread)), + worker_thread_(std::move(worker_thread)), + signaling_thread_(std::move(signaling_thread)), + encoder_factory_(encoder_factory), + decoder_factory_(decoder_factory), + network_monitor_factory_(network_monitor_factory), + factory_(factory) {} + + ~OwnedFactoryAndThreads(); + + PeerConnectionFactoryInterface* factory() { return factory_; } + Thread* signaling_thread() { return signaling_thread_.get(); } + Thread* worker_thread() { return worker_thread_.get(); } + WebRtcVideoEncoderFactory* encoder_factory() { return encoder_factory_; } + WebRtcVideoDecoderFactory* decoder_factory() { return decoder_factory_; } + rtc::NetworkMonitorFactory* network_monitor_factory() { + return network_monitor_factory_; + } + void clear_network_monitor_factory() { network_monitor_factory_ = nullptr; } + void InvokeJavaCallbacksOnFactoryThreads(); + + private: + void JavaCallbackOnFactoryThreads(); + + const std::unique_ptr network_thread_; + const std::unique_ptr worker_thread_; + const std::unique_ptr signaling_thread_; + WebRtcVideoEncoderFactory* encoder_factory_; + WebRtcVideoDecoderFactory* decoder_factory_; + rtc::NetworkMonitorFactory* network_monitor_factory_; + PeerConnectionFactoryInterface* factory_; // Const after ctor except dtor. +}; + +} // namespace webrtc_jni + +#endif // WEBRTC_SDK_ANDROID_SRC_JNI_OWNEDFACTORYANDTHREADS_H_ diff --git a/webrtc/sdk/android/src/jni/peerconnection_jni.cc b/webrtc/sdk/android/src/jni/peerconnection_jni.cc index dbe19af6f6..f257575964 100644 --- a/webrtc/sdk/android/src/jni/peerconnection_jni.cc +++ b/webrtc/sdk/android/src/jni/peerconnection_jni.cc @@ -61,26 +61,27 @@ #include "webrtc/base/ssladapter.h" #include "webrtc/base/stringutils.h" #include "webrtc/media/base/videocapturer.h" -#include "webrtc/media/engine/webrtcvideodecoderfactory.h" -#include "webrtc/media/engine/webrtcvideoencoderfactory.h" #include "webrtc/modules/utility/include/jvm_android.h" -#include "webrtc/system_wrappers/include/field_trial.h" #include "webrtc/pc/webrtcsdp.h" -#include "webrtc/sdk/android/src/jni/androidmediadecoder_jni.h" -#include "webrtc/sdk/android/src/jni/androidmediaencoder_jni.h" #include "webrtc/sdk/android/src/jni/androidnetworkmonitor_jni.h" -#include "webrtc/sdk/android/src/jni/androidvideotracksource.h" +// Adding 'nogncheck' to disable the gn include headers check. +// We don't want to always depend on audio and video related targets. +#include "webrtc/sdk/android/src/jni/androidvideotracksource.h" // nogncheck +#include "webrtc/sdk/android/src/jni/audio_jni.h" #include "webrtc/sdk/android/src/jni/classreferenceholder.h" #include "webrtc/sdk/android/src/jni/jni_helpers.h" -#include "webrtc/sdk/android/src/jni/native_handle_impl.h" +#include "webrtc/sdk/android/src/jni/media_jni.h" +#include "webrtc/sdk/android/src/jni/ownedfactoryandthreads.h" #include "webrtc/sdk/android/src/jni/rtcstatscollectorcallbackwrapper.h" +#include "webrtc/sdk/android/src/jni/video_jni.h" +#include "webrtc/system_wrappers/include/field_trial.h" // Adding 'nogncheck' to disable the gn include headers check. // We don't want to depend on 'system_wrappers:field_trial_default' because // clients should be able to provide their own implementation. #include "webrtc/system_wrappers/include/field_trial_default.h" // nogncheck #include "webrtc/system_wrappers/include/logcat_trace_context.h" #include "webrtc/system_wrappers/include/trace.h" -#include "webrtc/voice_engine/include/voe_base.h" +#include "webrtc/voice_engine/include/voe_base.h" // nogncheck using cricket::WebRtcVideoDecoderFactory; using cricket::WebRtcVideoEncoderFactory; @@ -113,10 +114,7 @@ using webrtc::SetSessionDescriptionObserver; using webrtc::StatsObserver; using webrtc::StatsReport; using webrtc::StatsReports; -using webrtc::VideoTrackSourceInterface; using webrtc::VideoTrackInterface; -using webrtc::VideoTrackVector; -using webrtc::kVideoCodecVP8; namespace webrtc_jni { @@ -846,125 +844,6 @@ class StatsObserverWrapper : public StatsObserver { const jmethodID j_value_ctor_; }; -// Wrapper dispatching rtc::VideoSinkInterface to a Java VideoRenderer -// instance. -class JavaVideoRendererWrapper - : public rtc::VideoSinkInterface { - public: - JavaVideoRendererWrapper(JNIEnv* jni, jobject j_callbacks) - : j_callbacks_(jni, j_callbacks), - j_render_frame_id_(GetMethodID( - jni, GetObjectClass(jni, j_callbacks), "renderFrame", - "(Lorg/webrtc/VideoRenderer$I420Frame;)V")), - j_frame_class_(jni, - FindClass(jni, "org/webrtc/VideoRenderer$I420Frame")), - j_i420_frame_ctor_id_(GetMethodID( - jni, *j_frame_class_, "", "(III[I[Ljava/nio/ByteBuffer;J)V")), - j_texture_frame_ctor_id_(GetMethodID( - jni, *j_frame_class_, "", - "(IIII[FJ)V")), - j_byte_buffer_class_(jni, FindClass(jni, "java/nio/ByteBuffer")) { - CHECK_EXCEPTION(jni); - } - - virtual ~JavaVideoRendererWrapper() {} - - void OnFrame(const webrtc::VideoFrame& video_frame) override { - ScopedLocalRefFrame local_ref_frame(jni()); - - jobject j_frame; - if (video_frame.video_frame_buffer()->type() == - webrtc::VideoFrameBuffer::Type::kNative) { - AndroidVideoFrameBuffer* android_buffer = - static_cast( - video_frame.video_frame_buffer().get()); - switch (android_buffer->android_type()) { - case AndroidVideoFrameBuffer::AndroidType::kTextureBuffer: - j_frame = ToJavaTextureFrame(&video_frame); - break; - case AndroidVideoFrameBuffer::AndroidType::kJavaBuffer: - j_frame = static_cast(android_buffer) - ->ToJavaI420Frame(jni(), video_frame.width(), - video_frame.height(), - video_frame.rotation()); - break; - default: - RTC_NOTREACHED(); - } - } else { - j_frame = ToJavaI420Frame(&video_frame); - } - // |j_callbacks_| is responsible for releasing |j_frame| with - // VideoRenderer.renderFrameDone(). - jni()->CallVoidMethod(*j_callbacks_, j_render_frame_id_, j_frame); - CHECK_EXCEPTION(jni()); - } - - private: - // Make a shallow copy of |frame| to be used with Java. The callee has - // ownership of the frame, and the frame should be released with - // VideoRenderer.releaseNativeFrame(). - static jlong javaShallowCopy(const webrtc::VideoFrame* frame) { - return jlongFromPointer(new webrtc::VideoFrame(*frame)); - } - - // Return a VideoRenderer.I420Frame referring to the data in |frame|. - jobject ToJavaI420Frame(const webrtc::VideoFrame* frame) { - jintArray strides = jni()->NewIntArray(3); - jint* strides_array = jni()->GetIntArrayElements(strides, NULL); - rtc::scoped_refptr i420_buffer = - frame->video_frame_buffer()->ToI420(); - strides_array[0] = i420_buffer->StrideY(); - strides_array[1] = i420_buffer->StrideU(); - strides_array[2] = i420_buffer->StrideV(); - jni()->ReleaseIntArrayElements(strides, strides_array, 0); - jobjectArray planes = jni()->NewObjectArray(3, *j_byte_buffer_class_, NULL); - jobject y_buffer = jni()->NewDirectByteBuffer( - const_cast(i420_buffer->DataY()), - i420_buffer->StrideY() * i420_buffer->height()); - size_t chroma_height = i420_buffer->ChromaHeight(); - jobject u_buffer = - jni()->NewDirectByteBuffer(const_cast(i420_buffer->DataU()), - i420_buffer->StrideU() * chroma_height); - jobject v_buffer = - jni()->NewDirectByteBuffer(const_cast(i420_buffer->DataV()), - i420_buffer->StrideV() * chroma_height); - - jni()->SetObjectArrayElement(planes, 0, y_buffer); - jni()->SetObjectArrayElement(planes, 1, u_buffer); - jni()->SetObjectArrayElement(planes, 2, v_buffer); - return jni()->NewObject( - *j_frame_class_, j_i420_frame_ctor_id_, - frame->width(), frame->height(), - static_cast(frame->rotation()), - strides, planes, javaShallowCopy(frame)); - } - - // Return a VideoRenderer.I420Frame referring texture object in |frame|. - jobject ToJavaTextureFrame(const webrtc::VideoFrame* frame) { - NativeHandleImpl handle = - static_cast(frame->video_frame_buffer().get()) - ->native_handle_impl(); - jfloatArray sampling_matrix = handle.sampling_matrix.ToJava(jni()); - - return jni()->NewObject( - *j_frame_class_, j_texture_frame_ctor_id_, frame->width(), - frame->height(), static_cast(frame->rotation()), - handle.oes_texture_id, sampling_matrix, javaShallowCopy(frame)); - } - - JNIEnv* jni() { - return AttachCurrentThreadIfNeeded(); - } - - ScopedGlobalRef j_callbacks_; - jmethodID j_render_frame_id_; - ScopedGlobalRef j_frame_class_; - jmethodID j_i420_frame_ctor_id_; - jmethodID j_texture_frame_ctor_id_; - ScopedGlobalRef j_byte_buffer_class_; -}; - // Adapter between the C++ RtpReceiverObserverInterface and the Java // RtpReceiver.Observer interface. Wraps an instance of the Java interface and // dispatches C++ callbacks to Java. @@ -1107,15 +986,6 @@ JOW(void, MediaSource_free)(JNIEnv*, jclass, jlong j_p) { reinterpret_cast(j_p)->Release(); } -JOW(void, VideoRenderer_freeWrappedVideoRenderer)(JNIEnv*, jclass, jlong j_p) { - delete reinterpret_cast(j_p); -} - -JOW(void, VideoRenderer_releaseNativeFrame)( - JNIEnv* jni, jclass, jlong j_frame_ptr) { - delete reinterpret_cast(j_frame_ptr); -} - JOW(void, MediaStreamTrack_free)(JNIEnv*, jclass, jlong j_p) { reinterpret_cast(j_p)->Release(); } @@ -1224,93 +1094,6 @@ JOW(void, AudioTrack_nativeSetVolume) source->SetVolume(volume); } -// Helper struct for working around the fact that CreatePeerConnectionFactory() -// comes in two flavors: either entirely automagical (constructing its own -// threads and deleting them on teardown, but no external codec factory support) -// or entirely manual (requires caller to delete threads after factory -// teardown). This struct takes ownership of its ctor's arguments to present a -// single thing for Java to hold and eventually free. -class OwnedFactoryAndThreads { - public: - OwnedFactoryAndThreads(std::unique_ptr network_thread, - std::unique_ptr worker_thread, - std::unique_ptr signaling_thread, - WebRtcVideoEncoderFactory* encoder_factory, - WebRtcVideoDecoderFactory* decoder_factory, - rtc::NetworkMonitorFactory* network_monitor_factory, - PeerConnectionFactoryInterface* factory) - : network_thread_(std::move(network_thread)), - worker_thread_(std::move(worker_thread)), - signaling_thread_(std::move(signaling_thread)), - encoder_factory_(encoder_factory), - decoder_factory_(decoder_factory), - network_monitor_factory_(network_monitor_factory), - factory_(factory) {} - - ~OwnedFactoryAndThreads() { - CHECK_RELEASE(factory_); - if (network_monitor_factory_ != nullptr) { - rtc::NetworkMonitorFactory::ReleaseFactory(network_monitor_factory_); - } - } - - PeerConnectionFactoryInterface* factory() { return factory_; } - Thread* signaling_thread() { return signaling_thread_.get(); } - Thread* worker_thread() { return worker_thread_.get(); } - WebRtcVideoEncoderFactory* encoder_factory() { return encoder_factory_; } - WebRtcVideoDecoderFactory* decoder_factory() { return decoder_factory_; } - rtc::NetworkMonitorFactory* network_monitor_factory() { - return network_monitor_factory_; - } - void clear_network_monitor_factory() { network_monitor_factory_ = nullptr; } - void InvokeJavaCallbacksOnFactoryThreads(); - - private: - void JavaCallbackOnFactoryThreads(); - - const std::unique_ptr network_thread_; - const std::unique_ptr worker_thread_; - const std::unique_ptr signaling_thread_; - WebRtcVideoEncoderFactory* encoder_factory_; - WebRtcVideoDecoderFactory* decoder_factory_; - rtc::NetworkMonitorFactory* network_monitor_factory_; - PeerConnectionFactoryInterface* factory_; // Const after ctor except dtor. -}; - -void OwnedFactoryAndThreads::JavaCallbackOnFactoryThreads() { - JNIEnv* jni = AttachCurrentThreadIfNeeded(); - ScopedLocalRefFrame local_ref_frame(jni); - jclass j_factory_class = FindClass(jni, "org/webrtc/PeerConnectionFactory"); - jmethodID m = nullptr; - if (network_thread_->IsCurrent()) { - LOG(LS_INFO) << "Network thread JavaCallback"; - m = GetStaticMethodID(jni, j_factory_class, "onNetworkThreadReady", "()V"); - } - if (worker_thread_->IsCurrent()) { - LOG(LS_INFO) << "Worker thread JavaCallback"; - m = GetStaticMethodID(jni, j_factory_class, "onWorkerThreadReady", "()V"); - } - if (signaling_thread_->IsCurrent()) { - LOG(LS_INFO) << "Signaling thread JavaCallback"; - m = GetStaticMethodID( - jni, j_factory_class, "onSignalingThreadReady", "()V"); - } - if (m != nullptr) { - jni->CallStaticVoidMethod(j_factory_class, m); - CHECK_EXCEPTION(jni) << "error during JavaCallback::CallStaticVoidMethod"; - } -} - -void OwnedFactoryAndThreads::InvokeJavaCallbacksOnFactoryThreads() { - LOG(LS_INFO) << "InvokeJavaCallbacksOnFactoryThreads."; - network_thread_->Invoke(RTC_FROM_HERE, - [this] { JavaCallbackOnFactoryThreads(); }); - worker_thread_->Invoke(RTC_FROM_HERE, - [this] { JavaCallbackOnFactoryThreads(); }); - signaling_thread_->Invoke(RTC_FROM_HERE, - [this] { JavaCallbackOnFactoryThreads(); }); -} - PeerConnectionFactoryInterface::Options ParseOptionsFromJava(JNIEnv* jni, jobject options) { jclass options_class = jni->GetObjectClass(options); @@ -1362,9 +1145,11 @@ JOW(jlong, PeerConnectionFactory_nativeCreatePeerConnectionFactory)( signaling_thread->SetName("signaling_thread", NULL); RTC_CHECK(signaling_thread->Start()) << "Failed to start thread"; - WebRtcVideoEncoderFactory* encoder_factory = nullptr; - WebRtcVideoDecoderFactory* decoder_factory = nullptr; + WebRtcVideoEncoderFactory* video_encoder_factory = nullptr; + WebRtcVideoDecoderFactory* video_decoder_factory = nullptr; rtc::NetworkMonitorFactory* network_monitor_factory = nullptr; + auto audio_encoder_factory = CreateAudioEncoderFactory(); + auto audio_decoder_factory = CreateAudioDecoderFactory(); PeerConnectionFactoryInterface::Options options; bool has_options = joptions != NULL; @@ -1373,8 +1158,8 @@ JOW(jlong, PeerConnectionFactory_nativeCreatePeerConnectionFactory)( } if (video_hw_acceleration_enabled) { - encoder_factory = new MediaCodecVideoEncoderFactory(); - decoder_factory = new MediaCodecVideoDecoderFactory(); + video_encoder_factory = CreateVideoEncoderFactory(); + video_decoder_factory = CreateVideoDecoderFactory(); } // Do not create network_monitor_factory only if the options are // provided and disable_network_monitor therein is set to true. @@ -1384,9 +1169,10 @@ JOW(jlong, PeerConnectionFactory_nativeCreatePeerConnectionFactory)( } rtc::scoped_refptr factory( - webrtc::CreatePeerConnectionFactory( + CreateNativePeerConnectionFactory( network_thread.get(), worker_thread.get(), signaling_thread.get(), - nullptr, encoder_factory, decoder_factory)); + nullptr, audio_encoder_factory, audio_decoder_factory, + video_encoder_factory, video_decoder_factory)); RTC_CHECK(factory) << "Failed to create the peer connection factory; " << "WebRTC/libjingle init likely failed on this device"; // TODO(honghaiz): Maybe put the options as the argument of @@ -1396,7 +1182,7 @@ JOW(jlong, PeerConnectionFactory_nativeCreatePeerConnectionFactory)( } OwnedFactoryAndThreads* owned_factory = new OwnedFactoryAndThreads( std::move(network_thread), std::move(worker_thread), - std::move(signaling_thread), encoder_factory, decoder_factory, + std::move(signaling_thread), video_encoder_factory, video_decoder_factory, network_monitor_factory, factory.release()); owned_factory->InvokeJavaCallbacksOnFactoryThreads(); return jlongFromPointer(owned_factory); @@ -1412,10 +1198,6 @@ JOW(void, PeerConnectionFactory_nativeFreeFactory)(JNIEnv*, jclass, jlong j_p) { webrtc::Trace::ReturnTrace(); } -static PeerConnectionFactoryInterface* factoryFromJava(jlong j_p) { - return reinterpret_cast(j_p)->factory(); -} - JOW(void, PeerConnectionFactory_nativeThreadsCallbacks)( JNIEnv*, jclass, jlong j_p) { OwnedFactoryAndThreads *factory = @@ -1432,37 +1214,6 @@ JOW(jlong, PeerConnectionFactory_nativeCreateLocalMediaStream)( return (jlong)stream.release(); } -JOW(jlong, PeerConnectionFactory_nativeCreateVideoSource) -(JNIEnv* jni, - jclass, - jlong native_factory, - jobject j_surface_texture_helper, - jboolean is_screencast) { - OwnedFactoryAndThreads* factory = - reinterpret_cast(native_factory); - - rtc::scoped_refptr source( - new rtc::RefCountedObject( - factory->signaling_thread(), jni, j_surface_texture_helper, - is_screencast)); - rtc::scoped_refptr proxy_source = - webrtc::VideoTrackSourceProxy::Create(factory->signaling_thread(), - factory->worker_thread(), source); - - return (jlong)proxy_source.release(); -} - -JOW(jlong, PeerConnectionFactory_nativeCreateVideoTrack)( - JNIEnv* jni, jclass, jlong native_factory, jstring id, - jlong native_source) { - rtc::scoped_refptr factory( - factoryFromJava(native_factory)); - rtc::scoped_refptr track(factory->CreateVideoTrack( - JavaToStdString(jni, id), - reinterpret_cast(native_source))); - return (jlong)track.release(); -} - JOW(jlong, PeerConnectionFactory_nativeCreateAudioSource)( JNIEnv* jni, jclass, jlong native_factory, jobject j_constraints) { std::unique_ptr constraints( @@ -1521,33 +1272,6 @@ JOW(void, PeerConnectionFactory_nativeSetOptions)( } } -JOW(void, PeerConnectionFactory_nativeSetVideoHwAccelerationOptions)( - JNIEnv* jni, jclass, jlong native_factory, jobject local_egl_context, - jobject remote_egl_context) { - OwnedFactoryAndThreads* owned_factory = - reinterpret_cast(native_factory); - - jclass j_eglbase14_context_class = - FindClass(jni, "org/webrtc/EglBase14$Context"); - - MediaCodecVideoEncoderFactory* encoder_factory = - static_cast - (owned_factory->encoder_factory()); - if (encoder_factory && - jni->IsInstanceOf(local_egl_context, j_eglbase14_context_class)) { - LOG(LS_INFO) << "Set EGL context for HW encoding."; - encoder_factory->SetEGLContext(jni, local_egl_context); - } - - MediaCodecVideoDecoderFactory* decoder_factory = - static_cast - (owned_factory->decoder_factory()); - if (decoder_factory) { - LOG(LS_INFO) << "Set EGL context for HW decoding."; - decoder_factory->SetEGLContext(jni, remote_egl_context); - } -} - static PeerConnectionInterface::IceTransportsType JavaIceTransportsTypeToNativeType(JNIEnv* jni, jobject j_ice_transports_type) { std::string enum_name = GetJavaEnumName( @@ -2184,39 +1908,6 @@ JOW(jobject, MediaSource_nativeState)(JNIEnv* jni, jclass, jlong j_p) { return JavaEnumFromIndex(jni, "MediaSource$State", p->state()); } -JOW(jlong, VideoRenderer_nativeWrapVideoRenderer)( - JNIEnv* jni, jclass, jobject j_callbacks) { - std::unique_ptr renderer( - new JavaVideoRendererWrapper(jni, j_callbacks)); - return (jlong)renderer.release(); -} - -JOW(void, VideoRenderer_nativeCopyPlane)( - JNIEnv *jni, jclass, jobject j_src_buffer, jint width, jint height, - jint src_stride, jobject j_dst_buffer, jint dst_stride) { - size_t src_size = jni->GetDirectBufferCapacity(j_src_buffer); - size_t dst_size = jni->GetDirectBufferCapacity(j_dst_buffer); - RTC_CHECK(src_stride >= width) << "Wrong source stride " << src_stride; - RTC_CHECK(dst_stride >= width) << "Wrong destination stride " << dst_stride; - RTC_CHECK(src_size >= src_stride * height) - << "Insufficient source buffer capacity " << src_size; - RTC_CHECK(dst_size >= dst_stride * height) - << "Insufficient destination buffer capacity " << dst_size; - uint8_t *src = - reinterpret_cast(jni->GetDirectBufferAddress(j_src_buffer)); - uint8_t *dst = - reinterpret_cast(jni->GetDirectBufferAddress(j_dst_buffer)); - if (src_stride == dst_stride) { - memcpy(dst, src, src_stride * height); - } else { - for (int i = 0; i < height; i++) { - memcpy(dst, src, width); - src += src_stride; - dst += dst_stride; - } - } -} - JOW(void, FileVideoCapturer_nativeI420ToNV21)( JNIEnv *jni, jclass, jbyteArray j_src_buffer, jint width, jint height, jbyteArray j_dst_buffer) { diff --git a/webrtc/sdk/android/src/jni/video_jni.cc b/webrtc/sdk/android/src/jni/video_jni.cc new file mode 100644 index 0000000000..cd3b4b2819 --- /dev/null +++ b/webrtc/sdk/android/src/jni/video_jni.cc @@ -0,0 +1,108 @@ +/* + * Copyright 2017 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 + +#include "webrtc/api/videosourceproxy.h" +#include "webrtc/base/logging.h" +#include "webrtc/media/engine/webrtcvideodecoderfactory.h" +#include "webrtc/media/engine/webrtcvideoencoderfactory.h" +#include "webrtc/sdk/android/src/jni/androidmediadecoder_jni.h" +#include "webrtc/sdk/android/src/jni/androidmediaencoder_jni.h" +#include "webrtc/sdk/android/src/jni/androidvideotracksource.h" +#include "webrtc/sdk/android/src/jni/classreferenceholder.h" +#include "webrtc/sdk/android/src/jni/ownedfactoryandthreads.h" +#include "webrtc/sdk/android/src/jni/surfacetexturehelper_jni.h" + +using cricket::WebRtcVideoDecoderFactory; +using cricket::WebRtcVideoEncoderFactory; +using webrtc::AndroidVideoTrackSource; +using webrtc::AudioSourceInterface; +using webrtc::VideoTrackSourceInterface; +using webrtc::VideoTrackInterface; + +namespace webrtc_jni { + +WebRtcVideoEncoderFactory* CreateVideoEncoderFactory() { + return new MediaCodecVideoEncoderFactory(); +} + +WebRtcVideoDecoderFactory* CreateVideoDecoderFactory() { + return new MediaCodecVideoDecoderFactory(); +} + +jobject GetJavaSurfaceTextureHelper( + rtc::scoped_refptr surface_texture_helper) { + return surface_texture_helper + ? surface_texture_helper->GetJavaSurfaceTextureHelper() + : nullptr; +} + +JOW(jlong, PeerConnectionFactory_nativeCreateVideoSource) +(JNIEnv* jni, + jclass, + jlong native_factory, + jobject j_surface_texture_helper, + jboolean is_screencast) { + OwnedFactoryAndThreads* factory = + reinterpret_cast(native_factory); + + rtc::scoped_refptr source( + new rtc::RefCountedObject( + factory->signaling_thread(), jni, j_surface_texture_helper, + is_screencast)); + rtc::scoped_refptr proxy_source = + webrtc::VideoTrackSourceProxy::Create(factory->signaling_thread(), + factory->worker_thread(), source); + + return (jlong)proxy_source.release(); +} + +JOW(jlong, PeerConnectionFactory_nativeCreateVideoTrack) +(JNIEnv* jni, jclass, jlong native_factory, jstring id, jlong native_source) { + rtc::scoped_refptr factory( + factoryFromJava(native_factory)); + rtc::scoped_refptr track(factory->CreateVideoTrack( + JavaToStdString(jni, id), + reinterpret_cast(native_source))); + return (jlong)track.release(); +} + +JOW(void, PeerConnectionFactory_nativeSetVideoHwAccelerationOptions) +(JNIEnv* jni, + jclass, + jlong native_factory, + jobject local_egl_context, + jobject remote_egl_context) { + OwnedFactoryAndThreads* owned_factory = + reinterpret_cast(native_factory); + + jclass j_eglbase14_context_class = + FindClass(jni, "org/webrtc/EglBase14$Context"); + + MediaCodecVideoEncoderFactory* encoder_factory = + static_cast( + owned_factory->encoder_factory()); + if (encoder_factory && + jni->IsInstanceOf(local_egl_context, j_eglbase14_context_class)) { + LOG(LS_INFO) << "Set EGL context for HW encoding."; + encoder_factory->SetEGLContext(jni, local_egl_context); + } + + MediaCodecVideoDecoderFactory* decoder_factory = + static_cast( + owned_factory->decoder_factory()); + if (decoder_factory) { + LOG(LS_INFO) << "Set EGL context for HW decoding."; + decoder_factory->SetEGLContext(jni, remote_egl_context); + } +} + +} // namespace webrtc_jni diff --git a/webrtc/sdk/android/src/jni/video_jni.h b/webrtc/sdk/android/src/jni/video_jni.h new file mode 100644 index 0000000000..9a885cdcad --- /dev/null +++ b/webrtc/sdk/android/src/jni/video_jni.h @@ -0,0 +1,32 @@ +/* + * Copyright 2017 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 WEBRTC_SDK_ANDROID_SRC_JNI_VIDEO_JNI_H_ +#define WEBRTC_SDK_ANDROID_SRC_JNI_VIDEO_JNI_H_ + +#include + +#include "webrtc/base/scoped_ref_ptr.h" +// Adding 'nogncheck' to disable the gn include headers check. +// We don't want this target depend on video related targets +#include "webrtc/sdk/android/src/jni/surfacetexturehelper_jni.h" // nogncheck + +namespace webrtc_jni { + +WebRtcVideoEncoderFactory* CreateVideoEncoderFactory(); + +WebRtcVideoDecoderFactory* CreateVideoDecoderFactory(); + +jobject GetJavaSurfaceTextureHelper( + rtc::scoped_refptr surface_texture_helper); + +} // namespace webrtc_jni + +#endif // WEBRTC_SDK_ANDROID_SRC_JNI_VIDEO_JNI_H_ diff --git a/webrtc/sdk/android/src/jni/video_renderer_jni.cc b/webrtc/sdk/android/src/jni/video_renderer_jni.cc new file mode 100644 index 0000000000..b5af0003f9 --- /dev/null +++ b/webrtc/sdk/android/src/jni/video_renderer_jni.cc @@ -0,0 +1,190 @@ +/* + * Copyright (c) 2017 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 +#undef JNIEXPORT +#define JNIEXPORT __attribute__((visibility("default"))) + +#include "webrtc/api/video/video_frame.h" +#include "webrtc/media/base/videosinkinterface.h" +#include "webrtc/sdk/android/src/jni/classreferenceholder.h" +#include "webrtc/sdk/android/src/jni/jni_helpers.h" +#include "webrtc/sdk/android/src/jni/native_handle_impl.h" + +namespace webrtc_jni { + +// Wrapper dispatching rtc::VideoSinkInterface to a Java VideoRenderer +// instance. +class JavaVideoRendererWrapper + : public rtc::VideoSinkInterface { + public: + JavaVideoRendererWrapper(JNIEnv* jni, jobject j_callbacks) + : j_callbacks_(jni, j_callbacks), + j_render_frame_id_( + GetMethodID(jni, + GetObjectClass(jni, j_callbacks), + "renderFrame", + "(Lorg/webrtc/VideoRenderer$I420Frame;)V")), + j_frame_class_(jni, + FindClass(jni, "org/webrtc/VideoRenderer$I420Frame")), + j_i420_frame_ctor_id_(GetMethodID(jni, + *j_frame_class_, + "", + "(III[I[Ljava/nio/ByteBuffer;J)V")), + j_texture_frame_ctor_id_( + GetMethodID(jni, *j_frame_class_, "", "(IIII[FJ)V")), + j_byte_buffer_class_(jni, FindClass(jni, "java/nio/ByteBuffer")) { + CHECK_EXCEPTION(jni); + } + + virtual ~JavaVideoRendererWrapper() {} + + void OnFrame(const webrtc::VideoFrame& video_frame) override { + ScopedLocalRefFrame local_ref_frame(jni()); + + jobject j_frame; + if (video_frame.video_frame_buffer()->type() == + webrtc::VideoFrameBuffer::Type::kNative) { + AndroidVideoFrameBuffer* android_buffer = + static_cast( + video_frame.video_frame_buffer().get()); + switch (android_buffer->android_type()) { + case AndroidVideoFrameBuffer::AndroidType::kTextureBuffer: + j_frame = ToJavaTextureFrame(&video_frame); + break; + case AndroidVideoFrameBuffer::AndroidType::kJavaBuffer: + j_frame = static_cast(android_buffer) + ->ToJavaI420Frame(jni(), video_frame.width(), + video_frame.height(), + video_frame.rotation()); + break; + default: + RTC_NOTREACHED(); + } + } else { + j_frame = ToJavaI420Frame(&video_frame); + } + // |j_callbacks_| is responsible for releasing |j_frame| with + // VideoRenderer.renderFrameDone(). + jni()->CallVoidMethod(*j_callbacks_, j_render_frame_id_, j_frame); + CHECK_EXCEPTION(jni()); + } + + private: + // Make a shallow copy of |frame| to be used with Java. The callee has + // ownership of the frame, and the frame should be released with + // VideoRenderer.releaseNativeFrame(). + static jlong javaShallowCopy(const webrtc::VideoFrame* frame) { + return jlongFromPointer(new webrtc::VideoFrame(*frame)); + } + + // Return a VideoRenderer.I420Frame referring to the data in |frame|. + jobject ToJavaI420Frame(const webrtc::VideoFrame* frame) { + jintArray strides = jni()->NewIntArray(3); + jint* strides_array = jni()->GetIntArrayElements(strides, NULL); + rtc::scoped_refptr i420_buffer = + frame->video_frame_buffer()->ToI420(); + strides_array[0] = i420_buffer->StrideY(); + strides_array[1] = i420_buffer->StrideU(); + strides_array[2] = i420_buffer->StrideV(); + jni()->ReleaseIntArrayElements(strides, strides_array, 0); + jobjectArray planes = jni()->NewObjectArray(3, *j_byte_buffer_class_, NULL); + jobject y_buffer = jni()->NewDirectByteBuffer( + const_cast(i420_buffer->DataY()), + i420_buffer->StrideY() * i420_buffer->height()); + size_t chroma_height = i420_buffer->ChromaHeight(); + jobject u_buffer = + jni()->NewDirectByteBuffer(const_cast(i420_buffer->DataU()), + i420_buffer->StrideU() * chroma_height); + jobject v_buffer = + jni()->NewDirectByteBuffer(const_cast(i420_buffer->DataV()), + i420_buffer->StrideV() * chroma_height); + + jni()->SetObjectArrayElement(planes, 0, y_buffer); + jni()->SetObjectArrayElement(planes, 1, u_buffer); + jni()->SetObjectArrayElement(planes, 2, v_buffer); + return jni()->NewObject(*j_frame_class_, j_i420_frame_ctor_id_, + frame->width(), frame->height(), + static_cast(frame->rotation()), strides, + planes, javaShallowCopy(frame)); + } + + // Return a VideoRenderer.I420Frame referring texture object in |frame|. + jobject ToJavaTextureFrame(const webrtc::VideoFrame* frame) { + NativeHandleImpl handle = + static_cast(frame->video_frame_buffer().get()) + ->native_handle_impl(); + jfloatArray sampling_matrix = handle.sampling_matrix.ToJava(jni()); + + return jni()->NewObject( + *j_frame_class_, j_texture_frame_ctor_id_, frame->width(), + frame->height(), static_cast(frame->rotation()), + handle.oes_texture_id, sampling_matrix, javaShallowCopy(frame)); + } + + JNIEnv* jni() { return AttachCurrentThreadIfNeeded(); } + + ScopedGlobalRef j_callbacks_; + jmethodID j_render_frame_id_; + ScopedGlobalRef j_frame_class_; + jmethodID j_i420_frame_ctor_id_; + jmethodID j_texture_frame_ctor_id_; + ScopedGlobalRef j_byte_buffer_class_; +}; + +JOW(void, VideoRenderer_freeWrappedVideoRenderer)(JNIEnv*, jclass, jlong j_p) { + delete reinterpret_cast(j_p); +} + +JOW(void, VideoRenderer_releaseNativeFrame) +(JNIEnv* jni, jclass, jlong j_frame_ptr) { + delete reinterpret_cast(j_frame_ptr); +} + +JOW(jlong, VideoRenderer_nativeWrapVideoRenderer) +(JNIEnv* jni, jclass, jobject j_callbacks) { + std::unique_ptr renderer( + new JavaVideoRendererWrapper(jni, j_callbacks)); + return (jlong)renderer.release(); +} + +JOW(void, VideoRenderer_nativeCopyPlane) +(JNIEnv* jni, + jclass, + jobject j_src_buffer, + jint width, + jint height, + jint src_stride, + jobject j_dst_buffer, + jint dst_stride) { + size_t src_size = jni->GetDirectBufferCapacity(j_src_buffer); + size_t dst_size = jni->GetDirectBufferCapacity(j_dst_buffer); + RTC_CHECK(src_stride >= width) << "Wrong source stride " << src_stride; + RTC_CHECK(dst_stride >= width) << "Wrong destination stride " << dst_stride; + RTC_CHECK(src_size >= src_stride * height) + << "Insufficient source buffer capacity " << src_size; + RTC_CHECK(dst_size >= dst_stride * height) + << "Insufficient destination buffer capacity " << dst_size; + uint8_t* src = + reinterpret_cast(jni->GetDirectBufferAddress(j_src_buffer)); + uint8_t* dst = + reinterpret_cast(jni->GetDirectBufferAddress(j_dst_buffer)); + if (src_stride == dst_stride) { + memcpy(dst, src, src_stride * height); + } else { + for (int i = 0; i < height; i++) { + memcpy(dst, src, width); + src += src_stride; + dst += dst_stride; + } + } +} + +} // namespace webrtc_jni