310 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
			
		
		
	
	
			310 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
| This directory contains an example Unity native plugin for Windows OS and Android.
 | |
| 
 | |
| The APIs use Platform Invoke (P/Invoke) technology as required by Unity native plugin.
 | |
| This plugin dll can also be used by Windows C# applications other than Unity.
 | |
| 
 | |
| For detailed build instruction on Android, see ANDROID_INSTRUCTION
 | |
| 
 | |
| An example of wrapping native plugin into a C# managed class in Unity is given as following:
 | |
| 
 | |
| using System;
 | |
| using System.Collections.Generic;
 | |
| using System.Runtime.InteropServices;
 | |
| 
 | |
| namespace SimplePeerConnectionM {
 | |
|   // A class for ice candidate.
 | |
|   public class IceCandidate {
 | |
|     public IceCandidate(string candidate, int sdpMlineIndex, string sdpMid) {
 | |
|       mCandidate = candidate;
 | |
|       mSdpMlineIndex = sdpMlineIndex;
 | |
|       mSdpMid = sdpMid;
 | |
|     }
 | |
|     string mCandidate;
 | |
|     int mSdpMlineIndex;
 | |
|     string mSdpMid;
 | |
| 
 | |
|     public string Candidate {
 | |
|       get { return mCandidate; }
 | |
|       set { mCandidate = value; }
 | |
|     }
 | |
| 
 | |
|     public int SdpMlineIndex {
 | |
|       get { return mSdpMlineIndex; }
 | |
|       set { mSdpMlineIndex = value; }
 | |
|     }
 | |
| 
 | |
|     public string SdpMid {
 | |
|       get { return mSdpMid; }
 | |
|       set { mSdpMid = value; }
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   // A managed wrapper up class for the native c style peer connection APIs.
 | |
|   public class PeerConnectionM {
 | |
|     private const string dllPath = "webrtc_unity_plugin";
 | |
| 
 | |
|     //create a peerconnection with turn servers
 | |
|     [DllImport(dllPath, CallingConvention = CallingConvention.Cdecl)]
 | |
|     private static extern int CreatePeerConnection(string[] turnUrls, int noOfUrls,
 | |
|         string username, string credential);
 | |
| 
 | |
|     [DllImport(dllPath, CallingConvention = CallingConvention.Cdecl)]
 | |
|     private static extern bool ClosePeerConnection(int peerConnectionId);
 | |
| 
 | |
|     [DllImport(dllPath, CallingConvention = CallingConvention.Cdecl)]
 | |
|     private static extern bool AddStream(int peerConnectionId, bool audioOnly);
 | |
| 
 | |
|     [DllImport(dllPath, CallingConvention = CallingConvention.Cdecl)]
 | |
|     private static extern bool AddDataChannel(int peerConnectionId);
 | |
| 
 | |
|     [DllImport(dllPath, CallingConvention = CallingConvention.Cdecl)]
 | |
|     private static extern bool CreateOffer(int peerConnectionId);
 | |
| 
 | |
|     [DllImport(dllPath, CallingConvention = CallingConvention.Cdecl)]
 | |
|     private static extern bool CreateAnswer(int peerConnectionId);
 | |
| 
 | |
|     [DllImport(dllPath, CallingConvention = CallingConvention.Cdecl)]
 | |
|     private static extern bool SendDataViaDataChannel(int peerConnectionId, string data);
 | |
| 
 | |
|     [DllImport(dllPath, CallingConvention = CallingConvention.Cdecl)]
 | |
|     private static extern bool SetAudioControl(int peerConnectionId, bool isMute, bool isRecord);
 | |
| 
 | |
|     [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
 | |
|     private delegate void LocalDataChannelReadyInternalDelegate();
 | |
|     public delegate void LocalDataChannelReadyDelegate(int id);
 | |
|     [DllImport(dllPath, CallingConvention = CallingConvention.Cdecl)]
 | |
|     private static extern bool RegisterOnLocalDataChannelReady(
 | |
|         int peerConnectionId, LocalDataChannelReadyInternalDelegate callback);
 | |
| 
 | |
|     [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
 | |
|     private delegate void DataFromDataChannelReadyInternalDelegate(string s);
 | |
|     public delegate void DataFromDataChannelReadyDelegate(int id, string s);
 | |
|     [DllImport(dllPath, CallingConvention = CallingConvention.Cdecl)]
 | |
|     private static extern bool RegisterOnDataFromDataChannelReady(
 | |
|         int peerConnectionId, DataFromDataChannelReadyInternalDelegate callback);
 | |
| 
 | |
|     [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
 | |
|     private delegate void FailureMessageInternalDelegate(string msg);
 | |
|     public delegate void FailureMessageDelegate(int id, string msg);
 | |
|     [DllImport(dllPath, CallingConvention = CallingConvention.Cdecl)]
 | |
|     private static extern bool RegisterOnFailure(int peerConnectionId,
 | |
|         FailureMessageInternalDelegate callback);
 | |
| 
 | |
|     [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
 | |
|     private delegate void AudioBusReadyInternalDelegate(IntPtr data, int bitsPerSample,
 | |
|         int sampleRate, int numberOfChannels, int numberOfFrames);
 | |
|     public delegate void AudioBusReadyDelegate(int id, IntPtr data, int bitsPerSample,
 | |
|         int sampleRate, int numberOfChannels, int numberOfFrames);
 | |
|     [DllImport(dllPath, CallingConvention = CallingConvention.Cdecl)]
 | |
|     private static extern bool RegisterOnAudioBusReady(int peerConnectionId,
 | |
|         AudioBusReadyInternalDelegate callback);
 | |
| 
 | |
|     // Video callbacks.
 | |
|     [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
 | |
|     private delegate void I420FrameReadyInternalDelegate(
 | |
|         IntPtr dataY, IntPtr dataU, IntPtr dataV,
 | |
|         int strideY, int strideU, int strideV,
 | |
|         uint width, uint height);
 | |
|     public delegate void I420FrameReadyDelegate(int id,
 | |
|         IntPtr dataY, IntPtr dataU, IntPtr dataV,
 | |
|         int strideY, int strideU, int strideV,
 | |
|         uint width, uint height);
 | |
|     [DllImport(dllPath, CallingConvention = CallingConvention.Cdecl)]
 | |
|     private static extern bool RegisterOnLocalI420FrameReady(int peerConnectionId,
 | |
|         I420FrameReadyInternalDelegate callback);
 | |
|     [DllImport(dllPath, CallingConvention = CallingConvention.Cdecl)]
 | |
|     private static extern bool RegisterOnRemoteI420FrameReady(int peerConnectionId,
 | |
|         I420FrameReadyInternalDelegate callback);
 | |
| 
 | |
|     [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
 | |
|     private delegate void LocalSdpReadytoSendInternalDelegate(string type, string sdp);
 | |
|     public delegate void LocalSdpReadytoSendDelegate(int id, string type, string sdp);
 | |
|     [DllImport(dllPath, CallingConvention = CallingConvention.Cdecl)]
 | |
|     private static extern bool RegisterOnLocalSdpReadytoSend(int peerConnectionId,
 | |
|         LocalSdpReadytoSendInternalDelegate callback);
 | |
| 
 | |
|     [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
 | |
|     private delegate void IceCandiateReadytoSendInternalDelegate(
 | |
|         string candidate, int sdpMlineIndex, string sdpMid);
 | |
|     public delegate void IceCandiateReadytoSendDelegate(
 | |
|         int id, string candidate, int sdpMlineIndex, string sdpMid);
 | |
|     [DllImport(dllPath, CallingConvention = CallingConvention.Cdecl)]
 | |
|     private static extern bool RegisterOnIceCandiateReadytoSend(
 | |
|         int peerConnectionId, IceCandiateReadytoSendInternalDelegate callback);
 | |
| 
 | |
|     [DllImport(dllPath, CallingConvention = CallingConvention.Cdecl)]
 | |
|     private static extern bool SetRemoteDescription(int peerConnectionId, string type, string sdp);
 | |
| 
 | |
|     [DllImport(dllPath, CallingConvention = CallingConvention.Cdecl)]
 | |
|     private static extern bool AddIceCandidate(int peerConnectionId, string sdp,
 | |
|       int sdpMlineindex, string sdpMid);
 | |
| 
 | |
|     public PeerConnectionM(List<string> turnUrls, string username, string credential) {
 | |
|       string[] urls = turnUrls != null ? turnUrls.ToArray() : null;
 | |
|       int length = turnUrls != null ? turnUrls.Count : 0;
 | |
|       mPeerConnectionId = CreatePeerConnection(urls, length, username, credential);
 | |
|       RegisterCallbacks();
 | |
|     }
 | |
| 
 | |
|     public void ClosePeerConnection() {
 | |
|       ClosePeerConnection(mPeerConnectionId);
 | |
|       mPeerConnectionId = -1;
 | |
|     }
 | |
| 
 | |
|     // Return -1 if Peerconnection is not available.
 | |
|     public int GetUniqueId() {
 | |
|       return mPeerConnectionId;
 | |
|     }
 | |
| 
 | |
|     public void AddStream(bool audioOnly) {
 | |
|       AddStream(mPeerConnectionId, audioOnly);
 | |
|     }
 | |
| 
 | |
|     public void AddDataChannel() {
 | |
|       AddDataChannel(mPeerConnectionId);
 | |
|     }
 | |
| 
 | |
|     public void CreateOffer() {
 | |
|       CreateOffer(mPeerConnectionId);
 | |
|     }
 | |
| 
 | |
|     public void CreateAnswer() {
 | |
|       CreateAnswer(mPeerConnectionId);
 | |
|     }
 | |
| 
 | |
|     public void SendDataViaDataChannel(string data) {
 | |
|       SendDataViaDataChannel(mPeerConnectionId, data);
 | |
|     }
 | |
| 
 | |
|     public void SetAudioControl(bool isMute, bool isRecord) {
 | |
|       SetAudioControl(mPeerConnectionId, isMute, isRecord);
 | |
|     }
 | |
| 
 | |
|     public void SetRemoteDescription(string type, string sdp) {
 | |
|       SetRemoteDescription(mPeerConnectionId, type, sdp);
 | |
|     }
 | |
| 
 | |
|     public void AddIceCandidate(string candidate, int sdpMlineindex, string sdpMid) {
 | |
|       AddIceCandidate(mPeerConnectionId, candidate, sdpMlineindex, sdpMid);
 | |
|     }
 | |
| 
 | |
|     private void RegisterCallbacks() {
 | |
|       localDataChannelReadyDelegate = new LocalDataChannelReadyInternalDelegate(
 | |
|           RaiseLocalDataChannelReady);
 | |
|       RegisterOnLocalDataChannelReady(mPeerConnectionId, localDataChannelReadyDelegate);
 | |
| 
 | |
|       dataFromDataChannelReadyDelegate = new DataFromDataChannelReadyInternalDelegate(
 | |
|           RaiseDataFromDataChannelReady);
 | |
|       RegisterOnDataFromDataChannelReady(mPeerConnectionId, dataFromDataChannelReadyDelegate);
 | |
| 
 | |
|       failureMessageDelegate = new FailureMessageInternalDelegate(RaiseFailureMessage);
 | |
|       RegisterOnFailure(mPeerConnectionId, failureMessageDelegate);
 | |
| 
 | |
|       audioBusReadyDelegate = new AudioBusReadyInternalDelegate(RaiseAudioBusReady);
 | |
|       RegisterOnAudioBusReady(mPeerConnectionId, audioBusReadyDelegate);
 | |
| 
 | |
|       localI420FrameReadyDelegate = new I420FrameReadyInternalDelegate(
 | |
|         RaiseLocalVideoFrameReady);
 | |
|       RegisterOnLocalI420FrameReady(mPeerConnectionId, localI420FrameReadyDelegate);
 | |
| 
 | |
|       remoteI420FrameReadyDelegate = new I420FrameReadyInternalDelegate(
 | |
|         RaiseRemoteVideoFrameReady);
 | |
|       RegisterOnRemoteI420FrameReady(mPeerConnectionId, remoteI420FrameReadyDelegate);
 | |
| 
 | |
|       localSdpReadytoSendDelegate = new LocalSdpReadytoSendInternalDelegate(
 | |
|         RaiseLocalSdpReadytoSend);
 | |
|       RegisterOnLocalSdpReadytoSend(mPeerConnectionId, localSdpReadytoSendDelegate);
 | |
| 
 | |
|       iceCandiateReadytoSendDelegate =
 | |
|           new IceCandiateReadytoSendInternalDelegate(RaiseIceCandiateReadytoSend);
 | |
|       RegisterOnIceCandiateReadytoSend(
 | |
|           mPeerConnectionId, iceCandiateReadytoSendDelegate);
 | |
|     }
 | |
| 
 | |
|     private void RaiseLocalDataChannelReady() {
 | |
|       if (OnLocalDataChannelReady != null)
 | |
|         OnLocalDataChannelReady(mPeerConnectionId);
 | |
|     }
 | |
| 
 | |
|     private void RaiseDataFromDataChannelReady(string data) {
 | |
|       if (OnDataFromDataChannelReady != null)
 | |
|         OnDataFromDataChannelReady(mPeerConnectionId, data);
 | |
|     }
 | |
| 
 | |
|     private void RaiseFailureMessage(string msg) {
 | |
|       if (OnFailureMessage != null)
 | |
|         OnFailureMessage(mPeerConnectionId, msg);
 | |
|     }
 | |
| 
 | |
|     private void RaiseAudioBusReady(IntPtr data, int bitsPerSample,
 | |
|       int sampleRate, int numberOfChannels, int numberOfFrames) {
 | |
|       if (OnAudioBusReady != null)
 | |
|         OnAudioBusReady(mPeerConnectionId, data, bitsPerSample, sampleRate,
 | |
|             numberOfChannels, numberOfFrames);
 | |
|     }
 | |
| 
 | |
|     private void RaiseLocalVideoFrameReady(
 | |
|         IntPtr dataY, IntPtr dataU, IntPtr dataV,
 | |
|         int strideY, int strideU, int strideV,
 | |
|         uint width, uint height) {
 | |
|       if (OnLocalVideoFrameReady != null)
 | |
|         OnLocalVideoFrameReady(mPeerConnectionId, dataY, dataU, dataV, strideY, strideU, strideV,
 | |
|           width, height);
 | |
|     }
 | |
| 
 | |
|     private void RaiseRemoteVideoFrameReady(
 | |
|        IntPtr dataY, IntPtr dataU, IntPtr dataV,
 | |
|        int strideY, int strideU, int strideV,
 | |
|        uint width, uint height) {
 | |
|       if (OnRemoteVideoFrameReady != null)
 | |
|         OnRemoteVideoFrameReady(mPeerConnectionId, dataY, dataU, dataV, strideY, strideU, strideV,
 | |
|           width, height);
 | |
|     }
 | |
| 
 | |
| 
 | |
|     private void RaiseLocalSdpReadytoSend(string type, string sdp) {
 | |
|       if (OnLocalSdpReadytoSend != null)
 | |
|         OnLocalSdpReadytoSend(mPeerConnectionId, type, sdp);
 | |
|     }
 | |
| 
 | |
|     private void RaiseIceCandiateReadytoSend(string candidate, int sdpMlineIndex, string sdpMid) {
 | |
|       if (OnIceCandiateReadytoSend != null)
 | |
|         OnIceCandiateReadytoSend(mPeerConnectionId, candidate, sdpMlineIndex, sdpMid);
 | |
|     }
 | |
| 
 | |
|     public void AddQueuedIceCandidate(List<IceCandidate> iceCandidateQueue) {
 | |
|       if (iceCandidateQueue != null) {
 | |
|         foreach (IceCandidate ic in iceCandidateQueue) {
 | |
|           AddIceCandidate(mPeerConnectionId, ic.Candidate, ic.SdpMlineIndex, ic.SdpMid);
 | |
|         }
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     private LocalDataChannelReadyInternalDelegate localDataChannelReadyDelegate = null;
 | |
|     public event LocalDataChannelReadyDelegate OnLocalDataChannelReady;
 | |
| 
 | |
|     private DataFromDataChannelReadyInternalDelegate dataFromDataChannelReadyDelegate = null;
 | |
|     public event DataFromDataChannelReadyDelegate OnDataFromDataChannelReady;
 | |
| 
 | |
|     private FailureMessageInternalDelegate failureMessageDelegate = null;
 | |
|     public event FailureMessageDelegate OnFailureMessage;
 | |
| 
 | |
|     private AudioBusReadyInternalDelegate audioBusReadyDelegate = null;
 | |
|     public event AudioBusReadyDelegate OnAudioBusReady;
 | |
| 
 | |
|     private I420FrameReadyInternalDelegate localI420FrameReadyDelegate = null;
 | |
|     public event I420FrameReadyDelegate OnLocalVideoFrameReady;
 | |
| 
 | |
|     private I420FrameReadyInternalDelegate remoteI420FrameReadyDelegate = null;
 | |
|     public event I420FrameReadyDelegate OnRemoteVideoFrameReady;
 | |
| 
 | |
|     private LocalSdpReadytoSendInternalDelegate localSdpReadytoSendDelegate = null;
 | |
|     public event LocalSdpReadytoSendDelegate OnLocalSdpReadytoSend;
 | |
| 
 | |
|     private IceCandiateReadytoSendInternalDelegate iceCandiateReadytoSendDelegate = null;
 | |
|     public event IceCandiateReadytoSendDelegate OnIceCandiateReadytoSend;
 | |
| 
 | |
|     private int mPeerConnectionId = -1;
 | |
|   }
 | |
| }
 |