如何使用 @CalledByNative("...")
?我需要来自 webrtc 库的回调。
如果你知道 PeerConnection 类就可以了:
这是 PeerConnection 的旧版本,但现在几乎相同
我调用了函数addStream
,但无法从中获取回调。
- 请解释
callbynative
的工作原理!
PeerConnection.java
/*
* Copyright 2013 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
package org.webrtc;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
/**
* Java-land version of the PeerConnection APIs; wraps the C++ API
* http://www.webrtc.org/reference/native-apis, which in turn is inspired by the
* JS APIs: http://dev.w3.org/2011/webrtc/editor/webrtc.html and
* http://www.w3.org/TR/mediacapture-streams/
*/
public class PeerConnection {
static {
System.loadLibrary("jingle_peerconnection_so");
}
/** Tracks PeerConnectionInterface::IceGatheringState */
public enum IceGatheringState { NEW, GATHERING, COMPLETE }
/** Tracks PeerConnectionInterface::IceConnectionState */
public enum IceConnectionState {
NEW,
CHECKING,
CONNECTED,
COMPLETED,
FAILED,
DISCONNECTED,
CLOSED
}
/** Tracks PeerConnectionInterface::SignalingState */
public enum SignalingState {
STABLE,
HAVE_LOCAL_OFFER,
HAVE_LOCAL_PRANSWER,
HAVE_REMOTE_OFFER,
HAVE_REMOTE_PRANSWER,
CLOSED
}
/** Java version of PeerConnectionObserver. */
public static interface Observer {
/** Triggered when the SignalingState changes. */
public void onSignalingChange(SignalingState newState);
/** Triggered when the IceConnectionState changes. */
public void onIceConnectionChange(IceConnectionState newState);
/** Triggered when the ICE connection receiving status changes. */
public void onIceConnectionReceivingChange(boolean receiving);
/** Triggered when the IceGatheringState changes. */
public void onIceGatheringChange(IceGatheringState newState);
/** Triggered when a new ICE candidate has been found. */
public void onIceCandidate(IceCandidate candidate);
/** Triggered when some ICE candidates have been removed. */
public void onIceCandidatesRemoved(IceCandidate[] candidates);
/** Triggered when media is received on a new stream from remote peer. */
public void onAddStream(MediaStream stream);
/** Triggered when a remote peer close a stream. */
public void onRemoveStream(MediaStream stream);
/** Triggered when a remote peer opens a DataChannel. */
public void onDataChannel(DataChannel dataChannel);
/** Triggered when renegotiation is necessary. */
public void onRenegotiationNeeded();
}
/** Java version of PeerConnectionInterface.IceServer. */
public static class IceServer {
public final String uri;
public final String username;
public final String password;
/** Convenience constructor for STUN servers. */
public IceServer(String uri) {
this(uri, "", "");
}
public IceServer(String uri, String username, String password) {
this.uri = uri;
this.username = username;
this.password = password;
}
public String toString() {
return uri + "[" + username + ":" + password + "]";
}
}
/** Java version of PeerConnectionInterface.IceTransportsType */
public enum IceTransportsType { NONE, RELAY, NOHOST, ALL }
/** Java version of PeerConnectionInterface.BundlePolicy */
public enum BundlePolicy { BALANCED, MAXBUNDLE, MAXCOMPAT }
/** Java version of PeerConnectionInterface.RtcpMuxPolicy */
public enum RtcpMuxPolicy { NEGOTIATE, REQUIRE }
/** Java version of PeerConnectionInterface.TcpCandidatePolicy */
public enum TcpCandidatePolicy { ENABLED, DISABLED }
/** Java version of PeerConnectionInterface.CandidateNetworkPolicy */
public enum CandidateNetworkPolicy { ALL, LOW_COST }
/** Java version of rtc::KeyType */
public enum KeyType { RSA, ECDSA }
/** Java version of PeerConnectionInterface.ContinualGatheringPolicy */
public enum ContinualGatheringPolicy { GATHER_ONCE, GATHER_CONTINUALLY }
/** Java version of PeerConnectionInterface.RTCConfiguration */
public static class RTCConfiguration {
public IceTransportsType iceTransportsType;
public List<IceServer> iceServers;
public BundlePolicy bundlePolicy;
public RtcpMuxPolicy rtcpMuxPolicy;
public TcpCandidatePolicy tcpCandidatePolicy;
public CandidateNetworkPolicy candidateNetworkPolicy;
public int audioJitterBufferMaxPackets;
public boolean audioJitterBufferFastAccelerate;
public int iceConnectionReceivingTimeout;
public int iceBackupCandidatePairPingInterval;
public KeyType keyType;
public ContinualGatheringPolicy continualGatheringPolicy;
public int iceCandidatePoolSize;
public boolean pruneTurnPorts;
public boolean presumeWritableWhenFullyRelayed;
public RTCConfiguration(List<IceServer> iceServers) {
iceTransportsType = IceTransportsType.ALL;
bundlePolicy = BundlePolicy.BALANCED;
rtcpMuxPolicy = RtcpMuxPolicy.NEGOTIATE;
tcpCandidatePolicy = TcpCandidatePolicy.ENABLED;
candidateNetworkPolicy = candidateNetworkPolicy.ALL;
this.iceServers = iceServers;
audioJitterBufferMaxPackets = 50;
audioJitterBufferFastAccelerate = false;
iceConnectionReceivingTimeout = -1;
iceBackupCandidatePairPingInterval = -1;
keyType = KeyType.ECDSA;
continualGatheringPolicy = ContinualGatheringPolicy.GATHER_ONCE;
iceCandidatePoolSize = 0;
pruneTurnPorts = false;
presumeWritableWhenFullyRelayed = false;
}
};
private final List<MediaStream> localStreams;
private final long nativePeerConnection;
private final long nativeObserver;
private List<RtpSender> senders;
private List<RtpReceiver> receivers;
PeerConnection(long nativePeerConnection, long nativeObserver) {
this.nativePeerConnection = nativePeerConnection;
this.nativeObserver = nativeObserver;
localStreams = new LinkedList<MediaStream>();
senders = new LinkedList<RtpSender>();
receivers = new LinkedList<RtpReceiver>();
}
// JsepInterface.
public native SessionDescription getLocalDescription();
public native SessionDescription getRemoteDescription();
public native DataChannel createDataChannel(String label, DataChannel.Init init);
public native void createOffer(SdpObserver observer, MediaConstraints constraints);
public native void createAnswer(SdpObserver observer, MediaConstraints constraints);
public native void setLocalDescription(SdpObserver observer, SessionDescription sdp);
public native void setRemoteDescription(SdpObserver observer, SessionDescription sdp);
public native boolean setConfiguration(RTCConfiguration config);
public boolean addIceCandidate(IceCandidate candidate) {
return nativeAddIceCandidate(candidate.sdpMid, candidate.sdpMLineIndex, candidate.sdp);
}
public boolean removeIceCandidates(final IceCandidate[] candidates) {
return nativeRemoveIceCandidates(candidates);
}
public boolean addStream(MediaStream stream) {
boolean ret = nativeAddLocalStream(stream.nativeStream);
if (!ret) {
return false;
}
localStreams.add(stream);
return true;
}
public void removeStream(MediaStream stream) {
nativeRemoveLocalStream(stream.nativeStream);
localStreams.remove(stream);
}
public RtpSender createSender(String kind, String stream_id) {
RtpSender new_sender = nativeCreateSender(kind, stream_id);
if (new_sender != null) {
senders.add(new_sender);
}
return new_sender;
}
// Note that calling getSenders will dispose of the senders previously
// returned (and same goes for getReceivers).
public List<RtpSender> getSenders() {
for (RtpSender sender : senders) {
sender.dispose();
}
senders = nativeGetSenders();
return Collections.unmodifiableList(senders);
}
public List<RtpReceiver> getReceivers() {
for (RtpReceiver receiver : receivers) {
receiver.dispose();
}
receivers = nativeGetReceivers();
return Collections.unmodifiableList(receivers);
}
public boolean getStats(StatsObserver observer, MediaStreamTrack track) {
return nativeGetStats(observer, (track == null) ? 0 : track.nativeTrack);
}
// Starts recording an RTC event log. Ownership of the file is transfered to
// the native code. If an RTC event log is already being recorded, it will be
// stopped and a new one will start using the provided file. Logging will
// continue until the stopRtcEventLog function is called. The max_size_bytes
// argument is ignored, it is added for future use.
public boolean startRtcEventLog(int file_descriptor, int max_size_bytes) {
return nativeStartRtcEventLog(file_descriptor, max_size_bytes);
}
// Stops recording an RTC event log. If no RTC event log is currently being
// recorded, this call will have no effect.
public void stopRtcEventLog() {
nativeStopRtcEventLog();
}
// TODO(fischman): add support for DTMF-related methods once that API
// stabilizes.
public native SignalingState signalingState();
public native IceConnectionState iceConnectionState();
public native IceGatheringState iceGatheringState();
public native void close();
public void dispose() {
close();
for (MediaStream stream : localStreams) {
nativeRemoveLocalStream(stream.nativeStream);
stream.dispose();
}
localStreams.clear();
for (RtpSender sender : senders) {
sender.dispose();
}
senders.clear();
for (RtpReceiver receiver : receivers) {
receiver.dispose();
}
receivers.clear();
freePeerConnection(nativePeerConnection);
freeObserver(nativeObserver);
}
private static native void freePeerConnection(long nativePeerConnection);
private static native void freeObserver(long nativeObserver);
private native boolean nativeAddIceCandidate(
String sdpMid, int sdpMLineIndex, String iceCandidateSdp);
private native boolean nativeRemoveIceCandidates(final IceCandidate[] candidates);
private native boolean nativeAddLocalStream(long nativeStream);
private native void nativeRemoveLocalStream(long nativeStream);
private native boolean nativeGetStats(StatsObserver observer, long nativeTrack);
private native RtpSender nativeCreateSender(String kind, String stream_id);
private native List<RtpSender> nativeGetSenders();
private native List<RtpReceiver> nativeGetReceivers();
private native boolean nativeStartRtcEventLog(int file_descriptor, int max_size_bytes);
private native void nativeStopRtcEventLog();
}
最佳答案
@CallByNative 是一个 annotation
,被 Google WebRtc 开发团队用来指定 Java 和 Native (C/C++
) 堆栈的 WebRtc 之间的映射。
正如官方 WebRtc Chromium Git 表示中所说,例如:
@CalledByNative is used by the JNI generator to create the necessary JNI bindings and expose this method to native code.
现在如果有一个问题是它是如何发生的? WebRtc Java 代码如何与 WebRtc Native Code 互通?
为此,我建议查看 WebRtc 的 native 代码对您的帮助最大。您将从 native 堆栈内的 Comments
中了解更多信息和相关内容。另一方面,你也应该具备
- Java 原生接口(interface) (JNI) 的工作原理
- WebRtc Java 和 Native Stack 是如何相互关联的
如需详细了解 Java 原生接口(interface),您可以访问以下引用资料:
这里我给你一个来自 PeerConnection.java
的例子。假设我们在 PeerConnection.java
类中有一个方法,例如:
@CalledByNative("IceGatheringState")
static IceGatheringState fromNativeIndex(int nativeIndex) {
return values()[nativeIndex];
}
现在这个方法映射到 src/sdk/android/src/jni/pc/peer_connection.cc
类中,例如:
static ScopedJavaLocalRef<jobject> JNI_PeerConnection_IceGatheringState(
JNIEnv* env,
const JavaParamRef<jobject>& j_pc) {
return Java_IceGatheringState_fromNativeIndex(
env, ExtractNativePC(env, j_pc)->ice_gathering_state());
}
如果您通过查看 PeerConnection
的 Java 和 Native 类来遵循相同的技术,您必须找到一些其他此类链接。现在,@CallByNative 在这里做了什么?
如果你看,在加载库之后,@CallByNative 基本上会做这两件事例如:
- 告诉方法属于哪个内部类
- 将此 Java 方法公开给 native 代码
- 使用 Java 和 native 代码进行 JNI 绑定(bind)
这些类型的注释由 Google Developers 提供,以便在使用 Pre-built libraries 时使 JNI 简单易懂。或您自己编译的库,例如 libwebrtc.aar
。
关于java - 什么是 '@CalledByNative(".. .")' ?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57974634/