| Index: webrtc/sdk/android/src/jni/pc/peerconnectionobserver_jni.cc
|
| diff --git a/webrtc/sdk/android/src/jni/pc/peerconnectionobserver_jni.cc b/webrtc/sdk/android/src/jni/pc/peerconnectionobserver_jni.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..18767925933ffb6006845d83b1fd2d3edb0954f5
|
| --- /dev/null
|
| +++ b/webrtc/sdk/android/src/jni/pc/peerconnectionobserver_jni.cc
|
| @@ -0,0 +1,307 @@
|
| +/*
|
| + * 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/pc/peerconnectionobserver_jni.h"
|
| +
|
| +#include <string>
|
| +
|
| +#include "webrtc/sdk/android/src/jni/classreferenceholder.h"
|
| +#include "webrtc/sdk/android/src/jni/pc/java_native_conversion.h"
|
| +
|
| +namespace webrtc_jni {
|
| +
|
| +// Convenience, used since callbacks occur on the signaling thread, which may
|
| +// be a non-Java thread.
|
| +static JNIEnv* jni() {
|
| + return AttachCurrentThreadIfNeeded();
|
| +}
|
| +
|
| +PeerConnectionObserverJni::PeerConnectionObserverJni(JNIEnv* jni,
|
| + jobject j_observer)
|
| + : j_observer_global_(jni, j_observer),
|
| + j_observer_class_(jni, GetObjectClass(jni, *j_observer_global_)),
|
| + j_media_stream_class_(jni, FindClass(jni, "org/webrtc/MediaStream")),
|
| + j_media_stream_ctor_(
|
| + GetMethodID(jni, *j_media_stream_class_, "<init>", "(J)V")),
|
| + j_audio_track_class_(jni, FindClass(jni, "org/webrtc/AudioTrack")),
|
| + j_audio_track_ctor_(
|
| + GetMethodID(jni, *j_audio_track_class_, "<init>", "(J)V")),
|
| + j_video_track_class_(jni, FindClass(jni, "org/webrtc/VideoTrack")),
|
| + j_video_track_ctor_(
|
| + GetMethodID(jni, *j_video_track_class_, "<init>", "(J)V")),
|
| + j_data_channel_class_(jni, FindClass(jni, "org/webrtc/DataChannel")),
|
| + j_data_channel_ctor_(
|
| + GetMethodID(jni, *j_data_channel_class_, "<init>", "(J)V")),
|
| + j_rtp_receiver_class_(jni, FindClass(jni, "org/webrtc/RtpReceiver")),
|
| + j_rtp_receiver_ctor_(
|
| + GetMethodID(jni, *j_rtp_receiver_class_, "<init>", "(J)V")) {}
|
| +
|
| +PeerConnectionObserverJni::~PeerConnectionObserverJni() {
|
| + ScopedLocalRefFrame local_ref_frame(jni());
|
| + while (!remote_streams_.empty())
|
| + DisposeRemoteStream(remote_streams_.begin());
|
| + while (!rtp_receivers_.empty())
|
| + DisposeRtpReceiver(rtp_receivers_.begin());
|
| +}
|
| +
|
| +void PeerConnectionObserverJni::OnIceCandidate(
|
| + const webrtc::IceCandidateInterface* candidate) {
|
| + ScopedLocalRefFrame local_ref_frame(jni());
|
| + std::string sdp;
|
| + RTC_CHECK(candidate->ToString(&sdp)) << "got so far: " << sdp;
|
| + jclass candidate_class = FindClass(jni(), "org/webrtc/IceCandidate");
|
| + jmethodID ctor =
|
| + GetMethodID(jni(), candidate_class, "<init>",
|
| + "(Ljava/lang/String;ILjava/lang/String;Ljava/lang/String;)V");
|
| + jstring j_mid = JavaStringFromStdString(jni(), candidate->sdp_mid());
|
| + jstring j_sdp = JavaStringFromStdString(jni(), sdp);
|
| + jstring j_url = JavaStringFromStdString(jni(), candidate->candidate().url());
|
| + jobject j_candidate = jni()->NewObject(
|
| + candidate_class, ctor, j_mid, candidate->sdp_mline_index(), j_sdp, j_url);
|
| + CHECK_EXCEPTION(jni()) << "error during NewObject";
|
| + jmethodID m = GetMethodID(jni(), *j_observer_class_, "onIceCandidate",
|
| + "(Lorg/webrtc/IceCandidate;)V");
|
| + jni()->CallVoidMethod(*j_observer_global_, m, j_candidate);
|
| + CHECK_EXCEPTION(jni()) << "error during CallVoidMethod";
|
| +}
|
| +
|
| +void PeerConnectionObserverJni::OnIceCandidatesRemoved(
|
| + const std::vector<cricket::Candidate>& candidates) {
|
| + ScopedLocalRefFrame local_ref_frame(jni());
|
| + jobjectArray candidates_array = NativeToJavaCandidateArray(jni(), candidates);
|
| + jmethodID m = GetMethodID(jni(), *j_observer_class_, "onIceCandidatesRemoved",
|
| + "([Lorg/webrtc/IceCandidate;)V");
|
| + jni()->CallVoidMethod(*j_observer_global_, m, candidates_array);
|
| + CHECK_EXCEPTION(jni()) << "Error during CallVoidMethod";
|
| +}
|
| +
|
| +void PeerConnectionObserverJni::OnSignalingChange(
|
| + webrtc::PeerConnectionInterface::SignalingState new_state) {
|
| + ScopedLocalRefFrame local_ref_frame(jni());
|
| + jmethodID m = GetMethodID(jni(), *j_observer_class_, "onSignalingChange",
|
| + "(Lorg/webrtc/PeerConnection$SignalingState;)V");
|
| + jobject new_state_enum = JavaEnumFromIndexAndClassName(
|
| + jni(), "PeerConnection$SignalingState", new_state);
|
| + jni()->CallVoidMethod(*j_observer_global_, m, new_state_enum);
|
| + CHECK_EXCEPTION(jni()) << "error during CallVoidMethod";
|
| +}
|
| +
|
| +void PeerConnectionObserverJni::OnIceConnectionChange(
|
| + webrtc::PeerConnectionInterface::IceConnectionState new_state) {
|
| + ScopedLocalRefFrame local_ref_frame(jni());
|
| + jmethodID m =
|
| + GetMethodID(jni(), *j_observer_class_, "onIceConnectionChange",
|
| + "(Lorg/webrtc/PeerConnection$IceConnectionState;)V");
|
| + jobject new_state_enum = JavaEnumFromIndexAndClassName(
|
| + jni(), "PeerConnection$IceConnectionState", new_state);
|
| + jni()->CallVoidMethod(*j_observer_global_, m, new_state_enum);
|
| + CHECK_EXCEPTION(jni()) << "error during CallVoidMethod";
|
| +}
|
| +
|
| +void PeerConnectionObserverJni::OnIceConnectionReceivingChange(bool receiving) {
|
| + ScopedLocalRefFrame local_ref_frame(jni());
|
| + jmethodID m = GetMethodID(jni(), *j_observer_class_,
|
| + "onIceConnectionReceivingChange", "(Z)V");
|
| + jni()->CallVoidMethod(*j_observer_global_, m, receiving);
|
| + CHECK_EXCEPTION(jni()) << "error during CallVoidMethod";
|
| +}
|
| +
|
| +void PeerConnectionObserverJni::OnIceGatheringChange(
|
| + webrtc::PeerConnectionInterface::IceGatheringState new_state) {
|
| + ScopedLocalRefFrame local_ref_frame(jni());
|
| + jmethodID m = GetMethodID(jni(), *j_observer_class_, "onIceGatheringChange",
|
| + "(Lorg/webrtc/PeerConnection$IceGatheringState;)V");
|
| + jobject new_state_enum = JavaEnumFromIndexAndClassName(
|
| + jni(), "PeerConnection$IceGatheringState", new_state);
|
| + jni()->CallVoidMethod(*j_observer_global_, m, new_state_enum);
|
| + CHECK_EXCEPTION(jni()) << "error during CallVoidMethod";
|
| +}
|
| +
|
| +void PeerConnectionObserverJni::OnAddStream(
|
| + rtc::scoped_refptr<webrtc::MediaStreamInterface> stream) {
|
| + ScopedLocalRefFrame local_ref_frame(jni());
|
| + // The stream could be added into the remote_streams_ map when calling
|
| + // OnAddTrack.
|
| + jobject j_stream = GetOrCreateJavaStream(stream);
|
| +
|
| + for (const auto& track : stream->GetAudioTracks()) {
|
| + jstring id = JavaStringFromStdString(jni(), track->id());
|
| + // Java AudioTrack holds one reference. Corresponding Release() is in
|
| + // MediaStreamTrack_free, triggered by AudioTrack.dispose().
|
| + track->AddRef();
|
| + jobject j_track =
|
| + jni()->NewObject(*j_audio_track_class_, j_audio_track_ctor_,
|
| + reinterpret_cast<jlong>(track.get()), id);
|
| + CHECK_EXCEPTION(jni()) << "error during NewObject";
|
| + jfieldID audio_tracks_id = GetFieldID(
|
| + jni(), *j_media_stream_class_, "audioTracks", "Ljava/util/LinkedList;");
|
| + jobject audio_tracks = GetObjectField(jni(), j_stream, audio_tracks_id);
|
| + jmethodID add = GetMethodID(jni(), GetObjectClass(jni(), audio_tracks),
|
| + "add", "(Ljava/lang/Object;)Z");
|
| + jboolean added = jni()->CallBooleanMethod(audio_tracks, add, j_track);
|
| + CHECK_EXCEPTION(jni()) << "error during CallBooleanMethod";
|
| + RTC_CHECK(added);
|
| + }
|
| +
|
| + for (const auto& track : stream->GetVideoTracks()) {
|
| + jstring id = JavaStringFromStdString(jni(), track->id());
|
| + // Java VideoTrack holds one reference. Corresponding Release() is in
|
| + // MediaStreamTrack_free, triggered by VideoTrack.dispose().
|
| + track->AddRef();
|
| + jobject j_track =
|
| + jni()->NewObject(*j_video_track_class_, j_video_track_ctor_,
|
| + reinterpret_cast<jlong>(track.get()), id);
|
| + CHECK_EXCEPTION(jni()) << "error during NewObject";
|
| + jfieldID video_tracks_id = GetFieldID(
|
| + jni(), *j_media_stream_class_, "videoTracks", "Ljava/util/LinkedList;");
|
| + jobject video_tracks = GetObjectField(jni(), j_stream, video_tracks_id);
|
| + jmethodID add = GetMethodID(jni(), GetObjectClass(jni(), video_tracks),
|
| + "add", "(Ljava/lang/Object;)Z");
|
| + jboolean added = jni()->CallBooleanMethod(video_tracks, add, j_track);
|
| + CHECK_EXCEPTION(jni()) << "error during CallBooleanMethod";
|
| + RTC_CHECK(added);
|
| + }
|
| +
|
| + jmethodID m = GetMethodID(jni(), *j_observer_class_, "onAddStream",
|
| + "(Lorg/webrtc/MediaStream;)V");
|
| + jni()->CallVoidMethod(*j_observer_global_, m, j_stream);
|
| + CHECK_EXCEPTION(jni()) << "error during CallVoidMethod";
|
| +}
|
| +
|
| +void PeerConnectionObserverJni::OnRemoveStream(
|
| + rtc::scoped_refptr<webrtc::MediaStreamInterface> stream) {
|
| + ScopedLocalRefFrame local_ref_frame(jni());
|
| + NativeToJavaStreamsMap::iterator it = remote_streams_.find(stream);
|
| + RTC_CHECK(it != remote_streams_.end())
|
| + << "unexpected stream: " << std::hex << stream;
|
| + jobject j_stream = it->second;
|
| + jmethodID m = GetMethodID(jni(), *j_observer_class_, "onRemoveStream",
|
| + "(Lorg/webrtc/MediaStream;)V");
|
| + jni()->CallVoidMethod(*j_observer_global_, m, j_stream);
|
| + CHECK_EXCEPTION(jni()) << "error during CallVoidMethod";
|
| + // Release the refptr reference so that DisposeRemoteStream can assert
|
| + // it removes the final reference.
|
| + stream = nullptr;
|
| + DisposeRemoteStream(it);
|
| +}
|
| +
|
| +void PeerConnectionObserverJni::OnDataChannel(
|
| + rtc::scoped_refptr<webrtc::DataChannelInterface> channel) {
|
| + ScopedLocalRefFrame local_ref_frame(jni());
|
| + jobject j_channel =
|
| + jni()->NewObject(*j_data_channel_class_, j_data_channel_ctor_,
|
| + jlongFromPointer(channel.get()));
|
| + CHECK_EXCEPTION(jni()) << "error during NewObject";
|
| +
|
| + jmethodID m = GetMethodID(jni(), *j_observer_class_, "onDataChannel",
|
| + "(Lorg/webrtc/DataChannel;)V");
|
| + jni()->CallVoidMethod(*j_observer_global_, m, j_channel);
|
| +
|
| + // Channel is now owned by Java object, and will be freed from
|
| + // DataChannel.dispose(). Important that this be done _after_ the
|
| + // CallVoidMethod above as Java code might call back into native code and be
|
| + // surprised to see a refcount of 2.
|
| + int bumped_count = channel->AddRef();
|
| + RTC_CHECK(bumped_count == 2) << "Unexpected refcount OnDataChannel";
|
| +
|
| + CHECK_EXCEPTION(jni()) << "error during CallVoidMethod";
|
| +}
|
| +
|
| +void PeerConnectionObserverJni::OnRenegotiationNeeded() {
|
| + ScopedLocalRefFrame local_ref_frame(jni());
|
| + jmethodID m =
|
| + GetMethodID(jni(), *j_observer_class_, "onRenegotiationNeeded", "()V");
|
| + jni()->CallVoidMethod(*j_observer_global_, m);
|
| + CHECK_EXCEPTION(jni()) << "error during CallVoidMethod";
|
| +}
|
| +
|
| +void PeerConnectionObserverJni::OnAddTrack(
|
| + rtc::scoped_refptr<webrtc::RtpReceiverInterface> receiver,
|
| + const std::vector<rtc::scoped_refptr<webrtc::MediaStreamInterface>>&
|
| + streams) {
|
| + ScopedLocalRefFrame local_ref_frame(jni());
|
| + jobject j_rtp_receiver =
|
| + jni()->NewObject(*j_rtp_receiver_class_, j_rtp_receiver_ctor_,
|
| + jlongFromPointer(receiver.get()));
|
| + CHECK_EXCEPTION(jni()) << "error during NewObject";
|
| + receiver->AddRef();
|
| + rtp_receivers_[receiver] = NewGlobalRef(jni(), j_rtp_receiver);
|
| +
|
| + jobjectArray j_stream_array = NativeToJavaMediaStreamArray(jni(), streams);
|
| + jmethodID m =
|
| + GetMethodID(jni(), *j_observer_class_, "onAddTrack",
|
| + "(Lorg/webrtc/RtpReceiver;[Lorg/webrtc/MediaStream;)V");
|
| + jni()->CallVoidMethod(*j_observer_global_, m, j_rtp_receiver, j_stream_array);
|
| + CHECK_EXCEPTION(jni()) << "Error during CallVoidMethod";
|
| +}
|
| +
|
| +void PeerConnectionObserverJni::SetConstraints(
|
| + MediaConstraintsJni* constraints) {
|
| + RTC_CHECK(!constraints_.get()) << "constraints already set!";
|
| + constraints_.reset(constraints);
|
| +}
|
| +
|
| +void PeerConnectionObserverJni::DisposeRemoteStream(
|
| + const NativeToJavaStreamsMap::iterator& it) {
|
| + jobject j_stream = it->second;
|
| + remote_streams_.erase(it);
|
| + jni()->CallVoidMethod(
|
| + j_stream, GetMethodID(jni(), *j_media_stream_class_, "dispose", "()V"));
|
| + CHECK_EXCEPTION(jni()) << "error during MediaStream.dispose()";
|
| + DeleteGlobalRef(jni(), j_stream);
|
| +}
|
| +
|
| +void PeerConnectionObserverJni::DisposeRtpReceiver(
|
| + const NativeToJavaRtpReceiverMap::iterator& it) {
|
| + jobject j_rtp_receiver = it->second;
|
| + rtp_receivers_.erase(it);
|
| + jni()->CallVoidMethod(
|
| + j_rtp_receiver,
|
| + GetMethodID(jni(), *j_rtp_receiver_class_, "dispose", "()V"));
|
| + CHECK_EXCEPTION(jni()) << "error during RtpReceiver.dispose()";
|
| + DeleteGlobalRef(jni(), j_rtp_receiver);
|
| +}
|
| +
|
| +// If the NativeToJavaStreamsMap contains the stream, return it.
|
| +// Otherwise, create a new Java MediaStream.
|
| +jobject PeerConnectionObserverJni::GetOrCreateJavaStream(
|
| + const rtc::scoped_refptr<webrtc::MediaStreamInterface>& stream) {
|
| + NativeToJavaStreamsMap::iterator it = remote_streams_.find(stream);
|
| + if (it != remote_streams_.end()) {
|
| + return it->second;
|
| + }
|
| +
|
| + // Java MediaStream holds one reference. Corresponding Release() is in
|
| + // MediaStream_free, triggered by MediaStream.dispose().
|
| + stream->AddRef();
|
| + jobject j_stream =
|
| + jni()->NewObject(*j_media_stream_class_, j_media_stream_ctor_,
|
| + reinterpret_cast<jlong>(stream.get()));
|
| + CHECK_EXCEPTION(jni()) << "error during NewObject";
|
| +
|
| + remote_streams_[stream] = NewGlobalRef(jni(), j_stream);
|
| + return j_stream;
|
| +}
|
| +
|
| +jobjectArray PeerConnectionObserverJni::NativeToJavaMediaStreamArray(
|
| + JNIEnv* jni,
|
| + const std::vector<rtc::scoped_refptr<webrtc::MediaStreamInterface>>&
|
| + streams) {
|
| + jobjectArray java_streams =
|
| + jni->NewObjectArray(streams.size(), *j_media_stream_class_, nullptr);
|
| + CHECK_EXCEPTION(jni) << "error during NewObjectArray";
|
| + for (size_t i = 0; i < streams.size(); ++i) {
|
| + jobject j_stream = GetOrCreateJavaStream(streams[i]);
|
| + jni->SetObjectArrayElement(java_streams, i, j_stream);
|
| + }
|
| + return java_streams;
|
| +}
|
| +
|
| +} // namespace webrtc_jni
|
|
|