Android WebRTC
原文链接:WebRTC之Android客户端
六、回调函数
1.WebSocket回调接口与主要消息处理
Candidate、answer、offer、bye四大类消息
private class WebSocketObserverimplements WebSocketConnectionObserver { @Override public void onOpen() { Log.d(TAG, "WebSocket connection opened to: " + wsServerUrl); executor.execute(new Runnable() { @Override public void run() { state = WebSocketConnectionState.CONNECTED; // Check if we have pending register request. if (roomID !=null && clientID != null) { register(roomID, clientID); } } }); } @Override public void onClose(WebSocketCloseNotification code, String reason) { Log.d(TAG, "WebSocket connection closed. Code: " + code + ". Reason: " + reason + ". State: " + state); synchronized (closeEventLock) { closeEvent = true; closeEventLock.notify(); } executor.execute(new Runnable() { @Override public void run() { if (state != WebSocketConnectionState.CLOSED) { state = WebSocketConnectionState.CLOSED; events.onWebSocketClose(); } } }); } @Override public void onTextMessage(String payload) { Log.d(TAG, "WSS->C: " + payload); final String message = payload; executor.execute(new Runnable() { @Override public void run() { if (state == WebSocketConnectionState.CONNECTED || state == WebSocketConnectionState.REGISTERED) { events.onWebSocketMessage(message); } } }); } @Override public void onRawTextMessage(byte[] payload) { } @Override public void onBinaryMessage(byte[] payload) { } } @Override public void onWebSocketMessage(final String msg) { if (wsClient.getState() != WebSocketConnectionState.REGISTERED) { Log.e(TAG, "Got WebSocket message in non registered state."); return; } try { JSONObject json = new JSONObject(msg); String msgText = json.getString("msg"); String errorText = json.optString("error"); if (msgText.length() > 0) { json = new JSONObject(msgText); String type = json.optString("type"); if (type.equals("candidate")) { IceCandidate candidate = new IceCandidate( json.getString("id"), json.getInt("label"), json.getString("candidate")); events.onRemoteIceCandidate(candidate); } else if (type.equals("answer")) { if (initiator) { SessionDescription sdp = new SessionDescription( SessionDescription.Type.fromCanonicalForm(type), json.getString("sdp")); events.onRemoteDescription(sdp); } else { reportError("Received answer for call initiator: " + msg); } } else if (type.equals("offer")) { if (!initiator) { SessionDescription sdp = new SessionDescription( SessionDescription.Type.fromCanonicalForm(type), json.getString("sdp")); events.onRemoteDescription(sdp); } else { reportError("Received offer for call receiver: " + msg); } } else if (type.equals("bye")) { events.onChannelClose(); } else { reportError("Unexpected WebSocket message: " + msg); } } else { if (errorText !=null && errorText.length() > 0) { reportError("WebSocket error message: " + errorText); } else { reportError("Unexpected WebSocket message: " + msg); } } } catch (JSONException e) { reportError("WebSocket message JSON parsing error: " + e.toString()); } }
2.Observer接口
主要是连接建立完成后Ice的改变和流信息的改变引起的回调
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 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(); }
3.SDP接口
主要是连接建立的过程中引起的回调
/** Interface for observing SDP-related events. */public interface SdpObserver { /** Called on success of Create{Offer,Answer}(). */ public void onCreateSuccess(SessionDescription sdp); /** Called on success of Set{Local,Remote}Description(). */ public void onSetSuccess(); /** Called on error of Create{Offer,Answer}(). */ public void onCreateFailure(String error); /** Called on error of Set{Local,Remote}Description(). */ public void onSetFailure(String error);}
4.PeerConnectionClient
生成PeerConnection,实现相关的回调,完成整个业务逻辑private final PCObserverpcObserver = new PCObserver();(Observer )private final SDPObserversdpObserver = new SDPObserver();(SdpObserver)private PeerConnectionFactoryfactory;private PeerConnectionpeerConnection;
5.CallActivity
private PeerConnectionClientpeerConnectionClient = null;private AppRTCClientappRtcClient;
七、Native函数之信令协商
6.1 加载so文件
static { System.loadLibrary("jingle_peerconnection_so"); }
6.2 PeerConnectionFactory相关Native函数
6.2.1网络接口相关参数
public static class Options { // Keep in sync with webrtc/base/network.h! static final int ADAPTER_TYPE_UNKNOWN = 0; static final int ADAPTER_TYPE_ETHERNET = 1 << 0; static final int ADAPTER_TYPE_WIFI = 1 << 1; static final int ADAPTER_TYPE_CELLULAR = 1 << 2; static final int ADAPTER_TYPE_VPN = 1 << 3; static final int ADAPTER_TYPE_LOOPBACK = 1 << 4; public int networkIgnoreMask; public boolean disableEncryption; }
6.2.2初始化PeerConnectionFactory
// |context| is an android.content.Context object, but we keep it untyped here // to allow building on non-Android platforms. // Callers may specify either |initializeAudio| or |initializeVideo| as false // to skip initializing the respective engine (and avoid the need for the // respective permissions). // |renderEGLContext| can be provided to suport HW video decoding to // texture and will be used to create a shared EGL context on video // decoding thread.public static native boolean initializeAndroidGlobals(Object context, boolean initializeAudio, boolean initializeVideo,boolean videoHwAcceleration);Context:简单的ApplicationContext,或者其他Context相关的上下文。initializeAudio:初始化音频部分。(boolean)videoHwAcceleration:是否启用硬件加速。(boolean)
6.2.3初始化音视频轨
private static final String FIELD_TRIAL_VP9 = "WebRTC-SupportVP9/Enabled/";// Field trial initialization. Must be called before PeerConnectionFactory // is created.public static native void initializeFieldTrials(String fieldTrialsInitString);
6.2.4 PeerConnectionFactory其他函数
//创建Factoryprivate static native long nativeCreatePeerConnectionFactory();//创建指令回调接口(与ICE服务器进行交互的指令)private static native long nativeCreateObserver(PeerConnection.Observer observer);//创建PeerConnectionprivate static native long nativeCreatePeerConnection(long nativeFactory, PeerConnection.RTCConfiguration rtcConfig, ediaConstraints constraints, long nativeObserver);//创建本地音视频流private static native long nativeCreateLocalMediaStream(long nativeFactory, String label);//创建本地视频源private static native long nativeCreateVideoSource(long nativeFactory, long nativeVideoCapturer, MediaConstraints constraints);//创建视频轨private static native long nativeCreateVideoTrack(long nativeFactory, String id, long nativeVideoSource);//创建本地音频流private static native long nativeCreateAudioSource(long nativeFactory, MediaConstraints constraints);//创建音频轨private static native long nativeCreateAudioTrack(long nativeFactory, String id, long nativeSource);//设置相关网络参数public native void nativeSetOptions(long nativeFactory, Options options);//设置视频硬件加速参数private static native void nativeSetVideoHwAccelerationOptions(long nativeFactory, Object renderEGLContext);//回收PeerConnectionFactoryprivate static native void freeFactory(long nativeFactory);
6.3 PeerConnection相关Native函数
6.3.1相关信令状态
//检测本地candidate的状态:刚刚创建、正在收集、完成收集** Tracks PeerConnectionInterface::IceGatheringState */ public enum IceGatheringState { NEW, GATHERING, COMPLETE }; //检测远端candidate的状态 /** Tracks PeerConnectionInterface::IceConnectionState */ public enum IceConnectionState { NEW, CHECKING, CONNECTED, COMPLETED, FAILED, DISCONNECTED, CLOSED }; //检测与Sigal信令服务器连接的状态 /** Tracks PeerConnectionInterface::SignalingState */ public enum SignalingState { STABLE, HAVE_LOCAL_OFFER, HAVE_LOCAL_PRANSWER, HAVE_REMOTE_OFFER, HAVE_REMOTE_PRANSWER, CLOSED };
6.3.2 Native函数介绍
//得到本地sdp描述public native SessionDescription getLocalDescription();//得到远端sdp描述public native SessionDescription getRemoteDescription();//创建数据通道public native DataChannel createDataChannel(String label, DataChannel.Init init);//创建offer消息public native void createOffer(SdpObserver observer, MediaConstraints constraints);//创建answer消息public native void createAnswer(SdpObserver observer, MediaConstraints constraints);//设置本地sdppublic native void setLocalDescription(SdpObserver observer, SessionDescription sdp);//设置远端sdppublic native void setRemoteDescription(SdpObserver observer, SessionDescription sdp);//更新IceServerpublic native boolean updateIce(List<IceServer> iceServers, MediaConstraints constraints);//得到信令状态public native SignalingState signalingState(); //获得远端连接状态public native IceConnectionState iceConnectionState();//获得本地连接状态public native IceGatheringState iceGatheringState();//关闭与Ice服务器的连接public native void close();//释放PeerConnectionprivate static native void freePeerConnection(long nativePeerConnection);//释放Observerprivate static native void freeObserver(long nativeObserver);//添加新的Candidateprivate native boolean nativeAddIceCandidate(String sdpMid, int sdpMLineIndex, String iceCandidateSdp);//添加本地流private native boolean nativeAddLocalStream(long nativeStream);//移除本地流private native void nativeRemoveLocalStream(long nativeStream);//得到StatsObserver的状态private native boolean nativeGetStats(StatsObserver observer, long nativeTrack);
八、Native函数之音视频
一旦有了peerConnectionFactory实例,就应该从你的设备上获取音频和视频了,最终渲染到屏幕上。VideoCapturerAndroid,VideoSource,VideoTrack和VideoRenderer,都是以VideoCapturerAndroid开始。
8.1 VideoCapturerAndroid
VideoCapturerAndroid类是一个相机的包装类,提供访问设备相机数据流的江边方法。允许你获取设备数量,获取前置后置摄像头
// Returns the number of camera devicesVideoCapturerAndroid.getDeviceCount();// Returns the front face device nameVideoCapturerAndroid.getNameOfFrontFacingDevice();// Returns the back facing device nameVideoCapturerAndroid.getNameOfBackFacingDevice(); // Creates a VideoCapturerAndroid instance for the device nameVideoCapturerAndroid.create(name);
使用VideoCapturerAndroid类的实例,可以创建包含相机视频流的MediaStream,你可以给对方发送数据。
8.2 VideoSource/VideoTrack
VideoSource可以开始或停止你的设备。在无用停止抓取信息有助于电池使用寿命的延长。
VideoTrack是一个添加VideoSource到MediaStream对象的一个包装。
8.3 AudioSource/AudioTrack
除了不需要AudioCapturer获取麦克风数据,AudioSource/AudioTrack和VideoSource/VideoTrack很类似。audioConstraints是MediaContraints的实例。
8.4 VideoRenderer
VideoRendererGui是一个GLSurfaceView,在这之上,可以显示视频流,增加我们的renderer到VideoTrack上。
// To create our VideoRenderer, we can use the// included VideoRendererGui for simplicity// First we need to set the GLSurfaceView that it should render toGLSurfaceView videoView = (GLSurfaceView) findViewById(R.id.glview_call);// Then we set that view, and pass a Runnable// to run once the surface is readyVideoRendererGui.setView(videoView, runnable);// Now that VideoRendererGui is ready, we can get our VideoRendererVideoRenderer renderer = VideoRendererGui.createGui(x, y, width, height);// And finally, with our VideoRenderer ready, we// can add our renderer to the VideoTrack.localVideoTrack.addRenderer(renderer);
8.5 MediaConstraints
这个MediaConstraints是WebRTC支持将视频和音频放入MediaStream的方式。看这个支持的规范,大多数方法都需要MediaContraints的实例。
8.6 MediaStream
getUserMedia直接返回一个MediaStream,可以直接将其添加到RTCPeerConnection中发送给对端。
// We start out with an empty MediaStream object,// created with help from our PeerConnectionFactory// Note that LOCAL_MEDIA_STREAM_ID can be any stringMediaStream mediaStream = peerConnectionFactory.createLocalMediaStream(LOCAL_MEDIA_STREAM_ID); // Now we can add our tracks.mediaStream.addTrack(localVideoTrack);mediaStream.addTrack(localAudioTrack);
更多相关文章
- C语言函数以及函数的使用
- android中去掉空格--trim函数
- Android使用videoview播放res/raw下的视频
- Android视频开发国人开发的Vitamio开源项目
- Android Q : 安卓源码、水滴屏适配状态栏图标(图标过多时显示一个
- android 动态控制状态栏显示和隐藏的方法实例
- android状态栏一体化(沉浸式状态栏)
- 移动端H5的Video标签无法播放在线视频的问题