Support building WebRTC without audio and video for Android
This CL makes the WebRTC Java Wrapper more modular and allows the android users to build WebRTC without audio and video(DataChannel only). The BUILD file in sdk/android/ is modified to support modular WebRTC. The peerconnection_jni.cc is split into peerconnection_jni.cc, video_jni.cc, video_renderer_jni.cc and ownedfactoryandthreads.h/cc. Add new modular build targets to JNI layer: audio_jni, video_jni, null_audio_jni, null_video_jni. The users can link with different targets to for different WebRTC functionalities. This is split from CL: https://codereview.webrtc.org/2854123003/ TBR=magjed@webrtc.org BUG=webrtc:7613 Review-Url: https://codereview.webrtc.org/2939203002 Cr-Commit-Position: refs/heads/master@{#18647}
This commit is contained in:
parent
d053fe4ab3
commit
af6293517f
@ -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"
|
||||
|
||||
@ -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<PeerConnection.IceServer> iceServers = new LinkedList<PeerConnection.IceServer>();
|
||||
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
|
||||
|
||||
@ -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",
|
||||
]
|
||||
|
||||
26
webrtc/sdk/android/src/jni/audio_jni.cc
Normal file
26
webrtc/sdk/android/src/jni/audio_jni.cc
Normal file
@ -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<webrtc::AudioDecoderFactory> CreateAudioDecoderFactory() {
|
||||
return webrtc::CreateBuiltinAudioDecoderFactory();
|
||||
}
|
||||
|
||||
rtc::scoped_refptr<webrtc::AudioEncoderFactory> CreateAudioEncoderFactory() {
|
||||
return webrtc::CreateBuiltinAudioEncoderFactory();
|
||||
}
|
||||
|
||||
} // namespace webrtc_jni
|
||||
28
webrtc/sdk/android/src/jni/audio_jni.h
Normal file
28
webrtc/sdk/android/src/jni/audio_jni.h
Normal file
@ -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<webrtc::AudioDecoderFactory> CreateAudioDecoderFactory();
|
||||
|
||||
rtc::scoped_refptr<webrtc::AudioEncoderFactory> CreateAudioEncoderFactory();
|
||||
|
||||
} // namespace webrtc_jni
|
||||
|
||||
#endif // WEBRTC_SDK_ANDROID_SRC_JNI_AUDIO_JNI_H_
|
||||
35
webrtc/sdk/android/src/jni/media_jni.cc
Normal file
35
webrtc/sdk/android/src/jni/media_jni.cc
Normal file
@ -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<webrtc::PeerConnectionFactoryInterface>
|
||||
CreateNativePeerConnectionFactory(
|
||||
rtc::Thread* network_thread,
|
||||
rtc::Thread* worker_thread,
|
||||
rtc::Thread* signaling_thread,
|
||||
webrtc::AudioDeviceModule* default_adm,
|
||||
rtc::scoped_refptr<webrtc::AudioEncoderFactory> audio_encoder_factory,
|
||||
rtc::scoped_refptr<webrtc::AudioDecoderFactory> 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
|
||||
33
webrtc/sdk/android/src/jni/media_jni.h
Normal file
33
webrtc/sdk/android/src/jni/media_jni.h
Normal file
@ -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<webrtc::PeerConnectionFactoryInterface>
|
||||
CreateNativePeerConnectionFactory(
|
||||
rtc::Thread* network_thread,
|
||||
rtc::Thread* worker_thread,
|
||||
rtc::Thread* signaling_thread,
|
||||
webrtc::AudioDeviceModule* default_adm,
|
||||
rtc::scoped_refptr<webrtc::AudioEncoderFactory> audio_encoder_factory,
|
||||
rtc::scoped_refptr<webrtc::AudioDecoderFactory> 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_
|
||||
22
webrtc/sdk/android/src/jni/null_audio_jni.cc
Normal file
22
webrtc/sdk/android/src/jni/null_audio_jni.cc
Normal file
@ -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<webrtc::AudioDecoderFactory> CreateAudioDecoderFactory() {
|
||||
return rtc::scoped_refptr<webrtc::AudioDecoderFactory>();
|
||||
}
|
||||
|
||||
rtc::scoped_refptr<webrtc::AudioEncoderFactory> CreateAudioEncoderFactory() {
|
||||
return rtc::scoped_refptr<webrtc::AudioEncoderFactory>();
|
||||
}
|
||||
|
||||
} // namespace webrtc_jni
|
||||
43
webrtc/sdk/android/src/jni/null_media_jni.cc
Normal file
43
webrtc/sdk/android/src/jni/null_media_jni.cc
Normal file
@ -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<webrtc::PeerConnectionFactoryInterface>
|
||||
CreateNativePeerConnectionFactory(
|
||||
rtc::Thread* network_thread,
|
||||
rtc::Thread* worker_thread,
|
||||
rtc::Thread* signaling_thread,
|
||||
webrtc::AudioDeviceModule* default_adm,
|
||||
rtc::scoped_refptr<webrtc::AudioEncoderFactory> audio_encoder_factory,
|
||||
rtc::scoped_refptr<webrtc::AudioDecoderFactory> 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<cricket::MediaEngineInterface>(),
|
||||
std::unique_ptr<webrtc::CallFactoryInterface>(),
|
||||
std::unique_ptr<webrtc::RtcEventLogFactoryInterface>());
|
||||
}
|
||||
|
||||
} // namespace webrtc_jni
|
||||
40
webrtc/sdk/android/src/jni/null_video_jni.cc
Normal file
40
webrtc/sdk/android/src/jni/null_video_jni.cc
Normal file
@ -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 <jni.h>
|
||||
|
||||
#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<SurfaceTextureHelper> surface_texture_helper) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
} // namespace webrtc_jni
|
||||
64
webrtc/sdk/android/src/jni/ownedfactoryandthreads.cc
Normal file
64
webrtc/sdk/android/src/jni/ownedfactoryandthreads.cc
Normal file
@ -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<OwnedFactoryAndThreads*>(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<void>(RTC_FROM_HERE,
|
||||
[this] { JavaCallbackOnFactoryThreads(); });
|
||||
worker_thread_->Invoke<void>(RTC_FROM_HERE,
|
||||
[this] { JavaCallbackOnFactoryThreads(); });
|
||||
signaling_thread_->Invoke<void>(RTC_FROM_HERE,
|
||||
[this] { JavaCallbackOnFactoryThreads(); });
|
||||
}
|
||||
|
||||
} // namespace webrtc_jni
|
||||
80
webrtc/sdk/android/src/jni/ownedfactoryandthreads.h
Normal file
80
webrtc/sdk/android/src/jni/ownedfactoryandthreads.h
Normal file
@ -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 <jni.h>
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
|
||||
#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<Thread> network_thread,
|
||||
std::unique_ptr<Thread> worker_thread,
|
||||
std::unique_ptr<Thread> 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<Thread> network_thread_;
|
||||
const std::unique_ptr<Thread> worker_thread_;
|
||||
const std::unique_ptr<Thread> 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_
|
||||
@ -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<webrtc::VideoFrame> {
|
||||
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_, "<init>", "(III[I[Ljava/nio/ByteBuffer;J)V")),
|
||||
j_texture_frame_ctor_id_(GetMethodID(
|
||||
jni, *j_frame_class_, "<init>",
|
||||
"(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<AndroidVideoFrameBuffer*>(
|
||||
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<AndroidVideoBuffer*>(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<webrtc::I420BufferInterface> 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<uint8_t*>(i420_buffer->DataY()),
|
||||
i420_buffer->StrideY() * i420_buffer->height());
|
||||
size_t chroma_height = i420_buffer->ChromaHeight();
|
||||
jobject u_buffer =
|
||||
jni()->NewDirectByteBuffer(const_cast<uint8_t*>(i420_buffer->DataU()),
|
||||
i420_buffer->StrideU() * chroma_height);
|
||||
jobject v_buffer =
|
||||
jni()->NewDirectByteBuffer(const_cast<uint8_t*>(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<int>(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<AndroidTextureBuffer*>(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<int>(frame->rotation()),
|
||||
handle.oes_texture_id, sampling_matrix, javaShallowCopy(frame));
|
||||
}
|
||||
|
||||
JNIEnv* jni() {
|
||||
return AttachCurrentThreadIfNeeded();
|
||||
}
|
||||
|
||||
ScopedGlobalRef<jobject> j_callbacks_;
|
||||
jmethodID j_render_frame_id_;
|
||||
ScopedGlobalRef<jclass> j_frame_class_;
|
||||
jmethodID j_i420_frame_ctor_id_;
|
||||
jmethodID j_texture_frame_ctor_id_;
|
||||
ScopedGlobalRef<jclass> 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<rtc::RefCountInterface*>(j_p)->Release();
|
||||
}
|
||||
|
||||
JOW(void, VideoRenderer_freeWrappedVideoRenderer)(JNIEnv*, jclass, jlong j_p) {
|
||||
delete reinterpret_cast<JavaVideoRendererWrapper*>(j_p);
|
||||
}
|
||||
|
||||
JOW(void, VideoRenderer_releaseNativeFrame)(
|
||||
JNIEnv* jni, jclass, jlong j_frame_ptr) {
|
||||
delete reinterpret_cast<const webrtc::VideoFrame*>(j_frame_ptr);
|
||||
}
|
||||
|
||||
JOW(void, MediaStreamTrack_free)(JNIEnv*, jclass, jlong j_p) {
|
||||
reinterpret_cast<MediaStreamTrackInterface*>(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<Thread> network_thread,
|
||||
std::unique_ptr<Thread> worker_thread,
|
||||
std::unique_ptr<Thread> 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<Thread> network_thread_;
|
||||
const std::unique_ptr<Thread> worker_thread_;
|
||||
const std::unique_ptr<Thread> 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<void>(RTC_FROM_HERE,
|
||||
[this] { JavaCallbackOnFactoryThreads(); });
|
||||
worker_thread_->Invoke<void>(RTC_FROM_HERE,
|
||||
[this] { JavaCallbackOnFactoryThreads(); });
|
||||
signaling_thread_->Invoke<void>(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<PeerConnectionFactoryInterface> 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<OwnedFactoryAndThreads*>(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<OwnedFactoryAndThreads*>(native_factory);
|
||||
|
||||
rtc::scoped_refptr<webrtc::AndroidVideoTrackSource> source(
|
||||
new rtc::RefCountedObject<webrtc::AndroidVideoTrackSource>(
|
||||
factory->signaling_thread(), jni, j_surface_texture_helper,
|
||||
is_screencast));
|
||||
rtc::scoped_refptr<webrtc::VideoTrackSourceProxy> 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<PeerConnectionFactoryInterface> factory(
|
||||
factoryFromJava(native_factory));
|
||||
rtc::scoped_refptr<VideoTrackInterface> track(factory->CreateVideoTrack(
|
||||
JavaToStdString(jni, id),
|
||||
reinterpret_cast<VideoTrackSourceInterface*>(native_source)));
|
||||
return (jlong)track.release();
|
||||
}
|
||||
|
||||
JOW(jlong, PeerConnectionFactory_nativeCreateAudioSource)(
|
||||
JNIEnv* jni, jclass, jlong native_factory, jobject j_constraints) {
|
||||
std::unique_ptr<ConstraintsWrapper> 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<OwnedFactoryAndThreads*>(native_factory);
|
||||
|
||||
jclass j_eglbase14_context_class =
|
||||
FindClass(jni, "org/webrtc/EglBase14$Context");
|
||||
|
||||
MediaCodecVideoEncoderFactory* encoder_factory =
|
||||
static_cast<MediaCodecVideoEncoderFactory*>
|
||||
(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<MediaCodecVideoDecoderFactory*>
|
||||
(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<JavaVideoRendererWrapper> 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<uint8_t*>(jni->GetDirectBufferAddress(j_src_buffer));
|
||||
uint8_t *dst =
|
||||
reinterpret_cast<uint8_t*>(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) {
|
||||
|
||||
108
webrtc/sdk/android/src/jni/video_jni.cc
Normal file
108
webrtc/sdk/android/src/jni/video_jni.cc
Normal file
@ -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 <jni.h>
|
||||
|
||||
#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<SurfaceTextureHelper> 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<OwnedFactoryAndThreads*>(native_factory);
|
||||
|
||||
rtc::scoped_refptr<webrtc::AndroidVideoTrackSource> source(
|
||||
new rtc::RefCountedObject<webrtc::AndroidVideoTrackSource>(
|
||||
factory->signaling_thread(), jni, j_surface_texture_helper,
|
||||
is_screencast));
|
||||
rtc::scoped_refptr<webrtc::VideoTrackSourceProxy> 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<PeerConnectionFactoryInterface> factory(
|
||||
factoryFromJava(native_factory));
|
||||
rtc::scoped_refptr<VideoTrackInterface> track(factory->CreateVideoTrack(
|
||||
JavaToStdString(jni, id),
|
||||
reinterpret_cast<VideoTrackSourceInterface*>(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<OwnedFactoryAndThreads*>(native_factory);
|
||||
|
||||
jclass j_eglbase14_context_class =
|
||||
FindClass(jni, "org/webrtc/EglBase14$Context");
|
||||
|
||||
MediaCodecVideoEncoderFactory* encoder_factory =
|
||||
static_cast<MediaCodecVideoEncoderFactory*>(
|
||||
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<MediaCodecVideoDecoderFactory*>(
|
||||
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
|
||||
32
webrtc/sdk/android/src/jni/video_jni.h
Normal file
32
webrtc/sdk/android/src/jni/video_jni.h
Normal file
@ -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 <jni.h>
|
||||
|
||||
#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<SurfaceTextureHelper> surface_texture_helper);
|
||||
|
||||
} // namespace webrtc_jni
|
||||
|
||||
#endif // WEBRTC_SDK_ANDROID_SRC_JNI_VIDEO_JNI_H_
|
||||
190
webrtc/sdk/android/src/jni/video_renderer_jni.cc
Normal file
190
webrtc/sdk/android/src/jni/video_renderer_jni.cc
Normal file
@ -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 <jni.h>
|
||||
#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<webrtc::VideoFrame> {
|
||||
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_,
|
||||
"<init>",
|
||||
"(III[I[Ljava/nio/ByteBuffer;J)V")),
|
||||
j_texture_frame_ctor_id_(
|
||||
GetMethodID(jni, *j_frame_class_, "<init>", "(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<AndroidVideoFrameBuffer*>(
|
||||
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<AndroidVideoBuffer*>(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<webrtc::I420BufferInterface> 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<uint8_t*>(i420_buffer->DataY()),
|
||||
i420_buffer->StrideY() * i420_buffer->height());
|
||||
size_t chroma_height = i420_buffer->ChromaHeight();
|
||||
jobject u_buffer =
|
||||
jni()->NewDirectByteBuffer(const_cast<uint8_t*>(i420_buffer->DataU()),
|
||||
i420_buffer->StrideU() * chroma_height);
|
||||
jobject v_buffer =
|
||||
jni()->NewDirectByteBuffer(const_cast<uint8_t*>(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<int>(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<AndroidTextureBuffer*>(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<int>(frame->rotation()),
|
||||
handle.oes_texture_id, sampling_matrix, javaShallowCopy(frame));
|
||||
}
|
||||
|
||||
JNIEnv* jni() { return AttachCurrentThreadIfNeeded(); }
|
||||
|
||||
ScopedGlobalRef<jobject> j_callbacks_;
|
||||
jmethodID j_render_frame_id_;
|
||||
ScopedGlobalRef<jclass> j_frame_class_;
|
||||
jmethodID j_i420_frame_ctor_id_;
|
||||
jmethodID j_texture_frame_ctor_id_;
|
||||
ScopedGlobalRef<jclass> j_byte_buffer_class_;
|
||||
};
|
||||
|
||||
JOW(void, VideoRenderer_freeWrappedVideoRenderer)(JNIEnv*, jclass, jlong j_p) {
|
||||
delete reinterpret_cast<JavaVideoRendererWrapper*>(j_p);
|
||||
}
|
||||
|
||||
JOW(void, VideoRenderer_releaseNativeFrame)
|
||||
(JNIEnv* jni, jclass, jlong j_frame_ptr) {
|
||||
delete reinterpret_cast<const webrtc::VideoFrame*>(j_frame_ptr);
|
||||
}
|
||||
|
||||
JOW(jlong, VideoRenderer_nativeWrapVideoRenderer)
|
||||
(JNIEnv* jni, jclass, jobject j_callbacks) {
|
||||
std::unique_ptr<JavaVideoRendererWrapper> 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<uint8_t*>(jni->GetDirectBufferAddress(j_src_buffer));
|
||||
uint8_t* dst =
|
||||
reinterpret_cast<uint8_t*>(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
|
||||
Loading…
x
Reference in New Issue
Block a user