blob: 5f26b89488c1c3b7ac9fa9b7c32eb30085af0e8d [file] [log] [blame]
qiangchen42f96d52017-08-08 17:08:03 -07001This directory contains an example Unity native plugin for Windows OS and Android.
2
gyzhouad7cad82017-05-11 16:10:03 -07003The APIs use Platform Invoke (P/Invoke) technology as required by Unity native plugin.
4This plugin dll can also be used by Windows C# applications other than Unity.
5
qiangchen42f96d52017-08-08 17:08:03 -07006For detailed build instruction on Android, see ANDROID_INSTRUCTION
7
gyzhouad7cad82017-05-11 16:10:03 -07008An example of wrapping native plugin into a C# managed class in Unity is given as following:
9
10using System;
gyzhoub38f3862017-07-25 16:04:31 -070011using System.Collections.Generic;
gyzhouad7cad82017-05-11 16:10:03 -070012using System.Runtime.InteropServices;
13
14namespace SimplePeerConnectionM {
gyzhoub38f3862017-07-25 16:04:31 -070015 // A class for ice candidate.
16 public class IceCandidate {
17 public IceCandidate(string candidate, int sdpMlineIndex, string sdpMid) {
18 mCandidate = candidate;
19 mSdpMlineIndex = sdpMlineIndex;
20 mSdpMid = sdpMid;
21 }
22 string mCandidate;
23 int mSdpMlineIndex;
24 string mSdpMid;
25
26 public string Candidate {
27 get { return mCandidate; }
28 set { mCandidate = value; }
29 }
30
31 public int SdpMlineIndex {
32 get { return mSdpMlineIndex; }
33 set { mSdpMlineIndex = value; }
34 }
35
36 public string SdpMid {
37 get { return mSdpMid; }
38 set { mSdpMid = value; }
39 }
40 }
41
42 // A managed wrapper up class for the native c style peer connection APIs.
gyzhouad7cad82017-05-11 16:10:03 -070043 public class PeerConnectionM {
gyzhoub38f3862017-07-25 16:04:31 -070044 private const string dllPath = "webrtc_unity_plugin";
gyzhouad7cad82017-05-11 16:10:03 -070045
gyzhoub38f3862017-07-25 16:04:31 -070046 //create a peerconnection with turn servers
47 [DllImport(dllPath, CallingConvention = CallingConvention.Cdecl)]
48 private static extern int CreatePeerConnection(string[] turnUrls, int noOfUrls,
49 string username, string credential);
gyzhouad7cad82017-05-11 16:10:03 -070050
gyzhoub38f3862017-07-25 16:04:31 -070051 [DllImport(dllPath, CallingConvention = CallingConvention.Cdecl)]
52 private static extern bool ClosePeerConnection(int peerConnectionId);
gyzhouad7cad82017-05-11 16:10:03 -070053
gyzhoub38f3862017-07-25 16:04:31 -070054 [DllImport(dllPath, CallingConvention = CallingConvention.Cdecl)]
55 private static extern bool AddStream(int peerConnectionId, bool audioOnly);
gyzhouad7cad82017-05-11 16:10:03 -070056
gyzhoub38f3862017-07-25 16:04:31 -070057 [DllImport(dllPath, CallingConvention = CallingConvention.Cdecl)]
58 private static extern bool AddDataChannel(int peerConnectionId);
gyzhouad7cad82017-05-11 16:10:03 -070059
gyzhoub38f3862017-07-25 16:04:31 -070060 [DllImport(dllPath, CallingConvention = CallingConvention.Cdecl)]
61 private static extern bool CreateOffer(int peerConnectionId);
gyzhouad7cad82017-05-11 16:10:03 -070062
gyzhoub38f3862017-07-25 16:04:31 -070063 [DllImport(dllPath, CallingConvention = CallingConvention.Cdecl)]
64 private static extern bool CreateAnswer(int peerConnectionId);
gyzhouad7cad82017-05-11 16:10:03 -070065
gyzhoub38f3862017-07-25 16:04:31 -070066 [DllImport(dllPath, CallingConvention = CallingConvention.Cdecl)]
67 private static extern bool SendDataViaDataChannel(int peerConnectionId, string data);
gyzhouad7cad82017-05-11 16:10:03 -070068
gyzhoub38f3862017-07-25 16:04:31 -070069 [DllImport(dllPath, CallingConvention = CallingConvention.Cdecl)]
70 private static extern bool SetAudioControl(int peerConnectionId, bool isMute, bool isRecord);
gyzhouad7cad82017-05-11 16:10:03 -070071
72 [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
73 private delegate void LocalDataChannelReadyInternalDelegate();
74 public delegate void LocalDataChannelReadyDelegate(int id);
gyzhoub38f3862017-07-25 16:04:31 -070075 [DllImport(dllPath, CallingConvention = CallingConvention.Cdecl)]
76 private static extern bool RegisterOnLocalDataChannelReady(
77 int peerConnectionId, LocalDataChannelReadyInternalDelegate callback);
gyzhouad7cad82017-05-11 16:10:03 -070078
79 [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
80 private delegate void DataFromDataChannelReadyInternalDelegate(string s);
81 public delegate void DataFromDataChannelReadyDelegate(int id, string s);
gyzhoub38f3862017-07-25 16:04:31 -070082 [DllImport(dllPath, CallingConvention = CallingConvention.Cdecl)]
83 private static extern bool RegisterOnDataFromDataChannelReady(
84 int peerConnectionId, DataFromDataChannelReadyInternalDelegate callback);
gyzhouad7cad82017-05-11 16:10:03 -070085
86 [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
87 private delegate void FailureMessageInternalDelegate(string msg);
88 public delegate void FailureMessageDelegate(int id, string msg);
gyzhoub38f3862017-07-25 16:04:31 -070089 [DllImport(dllPath, CallingConvention = CallingConvention.Cdecl)]
90 private static extern bool RegisterOnFailure(int peerConnectionId,
91 FailureMessageInternalDelegate callback);
gyzhouad7cad82017-05-11 16:10:03 -070092
93 [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
gyzhoub38f3862017-07-25 16:04:31 -070094 private delegate void AudioBusReadyInternalDelegate(IntPtr data, int bitsPerSample,
95 int sampleRate, int numberOfChannels, int numberOfFrames);
96 public delegate void AudioBusReadyDelegate(int id, IntPtr data, int bitsPerSample,
97 int sampleRate, int numberOfChannels, int numberOfFrames);
98 [DllImport(dllPath, CallingConvention = CallingConvention.Cdecl)]
99 private static extern bool RegisterOnAudioBusReady(int peerConnectionId,
100 AudioBusReadyInternalDelegate callback);
101
102 // Video callbacks.
103 [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
104 private delegate void I420FrameReadyInternalDelegate(
105 IntPtr dataY, IntPtr dataU, IntPtr dataV,
106 int strideY, int strideU, int strideV,
107 uint width, uint height);
108 public delegate void I420FrameReadyDelegate(int id,
109 IntPtr dataY, IntPtr dataU, IntPtr dataV,
110 int strideY, int strideU, int strideV,
111 uint width, uint height);
112 [DllImport(dllPath, CallingConvention = CallingConvention.Cdecl)]
113 private static extern bool RegisterOnLocalI420FrameReady(int peerConnectionId,
114 I420FrameReadyInternalDelegate callback);
115 [DllImport(dllPath, CallingConvention = CallingConvention.Cdecl)]
116 private static extern bool RegisterOnRemoteI420FrameReady(int peerConnectionId,
117 I420FrameReadyInternalDelegate callback);
gyzhouad7cad82017-05-11 16:10:03 -0700118
119 [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
gyzhoub38f3862017-07-25 16:04:31 -0700120 private delegate void LocalSdpReadytoSendInternalDelegate(string type, string sdp);
121 public delegate void LocalSdpReadytoSendDelegate(int id, string type, string sdp);
122 [DllImport(dllPath, CallingConvention = CallingConvention.Cdecl)]
123 private static extern bool RegisterOnLocalSdpReadytoSend(int peerConnectionId,
124 LocalSdpReadytoSendInternalDelegate callback);
gyzhouad7cad82017-05-11 16:10:03 -0700125
126 [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
gyzhoub38f3862017-07-25 16:04:31 -0700127 private delegate void IceCandiateReadytoSendInternalDelegate(
128 string candidate, int sdpMlineIndex, string sdpMid);
129 public delegate void IceCandiateReadytoSendDelegate(
130 int id, string candidate, int sdpMlineIndex, string sdpMid);
131 [DllImport(dllPath, CallingConvention = CallingConvention.Cdecl)]
132 private static extern bool RegisterOnIceCandiateReadytoSend(
133 int peerConnectionId, IceCandiateReadytoSendInternalDelegate callback);
gyzhouad7cad82017-05-11 16:10:03 -0700134
gyzhoub38f3862017-07-25 16:04:31 -0700135 [DllImport(dllPath, CallingConvention = CallingConvention.Cdecl)]
136 private static extern bool SetRemoteDescription(int peerConnectionId, string type, string sdp);
gyzhouad7cad82017-05-11 16:10:03 -0700137
gyzhoub38f3862017-07-25 16:04:31 -0700138 [DllImport(dllPath, CallingConvention = CallingConvention.Cdecl)]
139 private static extern bool AddIceCandidate(int peerConnectionId, string sdp,
140 int sdpMlineindex, string sdpMid);
gyzhouad7cad82017-05-11 16:10:03 -0700141
gyzhoub38f3862017-07-25 16:04:31 -0700142 public PeerConnectionM(List<string> turnUrls, string username, string credential) {
143 string[] urls = turnUrls != null ? turnUrls.ToArray() : null;
144 int length = turnUrls != null ? turnUrls.Count : 0;
145 mPeerConnectionId = CreatePeerConnection(urls, length, username, credential);
gyzhouad7cad82017-05-11 16:10:03 -0700146 RegisterCallbacks();
147 }
148
gyzhoub38f3862017-07-25 16:04:31 -0700149 public void ClosePeerConnection() {
150 ClosePeerConnection(mPeerConnectionId);
151 mPeerConnectionId = -1;
gyzhouad7cad82017-05-11 16:10:03 -0700152 }
153
154 // Return -1 if Peerconnection is not available.
155 public int GetUniqueId() {
gyzhoub38f3862017-07-25 16:04:31 -0700156 return mPeerConnectionId;
gyzhouad7cad82017-05-11 16:10:03 -0700157 }
158
gyzhoub38f3862017-07-25 16:04:31 -0700159 public void AddStream(bool audioOnly) {
160 AddStream(mPeerConnectionId, audioOnly);
gyzhouad7cad82017-05-11 16:10:03 -0700161 }
162
gyzhoub38f3862017-07-25 16:04:31 -0700163 public void AddDataChannel() {
164 AddDataChannel(mPeerConnectionId);
gyzhouad7cad82017-05-11 16:10:03 -0700165 }
166
gyzhoub38f3862017-07-25 16:04:31 -0700167 public void CreateOffer() {
168 CreateOffer(mPeerConnectionId);
gyzhouad7cad82017-05-11 16:10:03 -0700169 }
170
gyzhoub38f3862017-07-25 16:04:31 -0700171 public void CreateAnswer() {
172 CreateAnswer(mPeerConnectionId);
gyzhouad7cad82017-05-11 16:10:03 -0700173 }
174
gyzhoub38f3862017-07-25 16:04:31 -0700175 public void SendDataViaDataChannel(string data) {
176 SendDataViaDataChannel(mPeerConnectionId, data);
gyzhouad7cad82017-05-11 16:10:03 -0700177 }
178
gyzhoub38f3862017-07-25 16:04:31 -0700179 public void SetAudioControl(bool isMute, bool isRecord) {
180 SetAudioControl(mPeerConnectionId, isMute, isRecord);
gyzhouad7cad82017-05-11 16:10:03 -0700181 }
182
gyzhoub38f3862017-07-25 16:04:31 -0700183 public void SetRemoteDescription(string type, string sdp) {
184 SetRemoteDescription(mPeerConnectionId, type, sdp);
gyzhouad7cad82017-05-11 16:10:03 -0700185 }
186
gyzhoub38f3862017-07-25 16:04:31 -0700187 public void AddIceCandidate(string candidate, int sdpMlineindex, string sdpMid) {
188 AddIceCandidate(mPeerConnectionId, candidate, sdpMlineindex, sdpMid);
189 }
190
191 private void RegisterCallbacks() {
192 localDataChannelReadyDelegate = new LocalDataChannelReadyInternalDelegate(
193 RaiseLocalDataChannelReady);
194 RegisterOnLocalDataChannelReady(mPeerConnectionId, localDataChannelReadyDelegate);
195
196 dataFromDataChannelReadyDelegate = new DataFromDataChannelReadyInternalDelegate(
197 RaiseDataFromDataChannelReady);
198 RegisterOnDataFromDataChannelReady(mPeerConnectionId, dataFromDataChannelReadyDelegate);
199
200 failureMessageDelegate = new FailureMessageInternalDelegate(RaiseFailureMessage);
201 RegisterOnFailure(mPeerConnectionId, failureMessageDelegate);
202
203 audioBusReadyDelegate = new AudioBusReadyInternalDelegate(RaiseAudioBusReady);
204 RegisterOnAudioBusReady(mPeerConnectionId, audioBusReadyDelegate);
205
206 localI420FrameReadyDelegate = new I420FrameReadyInternalDelegate(
207 RaiseLocalVideoFrameReady);
208 RegisterOnLocalI420FrameReady(mPeerConnectionId, localI420FrameReadyDelegate);
209
210 remoteI420FrameReadyDelegate = new I420FrameReadyInternalDelegate(
211 RaiseRemoteVideoFrameReady);
212 RegisterOnRemoteI420FrameReady(mPeerConnectionId, remoteI420FrameReadyDelegate);
213
214 localSdpReadytoSendDelegate = new LocalSdpReadytoSendInternalDelegate(
215 RaiseLocalSdpReadytoSend);
216 RegisterOnLocalSdpReadytoSend(mPeerConnectionId, localSdpReadytoSendDelegate);
217
218 iceCandiateReadytoSendDelegate =
219 new IceCandiateReadytoSendInternalDelegate(RaiseIceCandiateReadytoSend);
220 RegisterOnIceCandiateReadytoSend(
221 mPeerConnectionId, iceCandiateReadytoSendDelegate);
gyzhouad7cad82017-05-11 16:10:03 -0700222 }
223
224 private void RaiseLocalDataChannelReady() {
225 if (OnLocalDataChannelReady != null)
gyzhoub38f3862017-07-25 16:04:31 -0700226 OnLocalDataChannelReady(mPeerConnectionId);
gyzhouad7cad82017-05-11 16:10:03 -0700227 }
228
229 private void RaiseDataFromDataChannelReady(string data) {
230 if (OnDataFromDataChannelReady != null)
gyzhoub38f3862017-07-25 16:04:31 -0700231 OnDataFromDataChannelReady(mPeerConnectionId, data);
gyzhouad7cad82017-05-11 16:10:03 -0700232 }
233
234 private void RaiseFailureMessage(string msg) {
235 if (OnFailureMessage != null)
gyzhoub38f3862017-07-25 16:04:31 -0700236 OnFailureMessage(mPeerConnectionId, msg);
gyzhouad7cad82017-05-11 16:10:03 -0700237 }
238
gyzhoub38f3862017-07-25 16:04:31 -0700239 private void RaiseAudioBusReady(IntPtr data, int bitsPerSample,
240 int sampleRate, int numberOfChannels, int numberOfFrames) {
gyzhouad7cad82017-05-11 16:10:03 -0700241 if (OnAudioBusReady != null)
gyzhoub38f3862017-07-25 16:04:31 -0700242 OnAudioBusReady(mPeerConnectionId, data, bitsPerSample, sampleRate,
243 numberOfChannels, numberOfFrames);
gyzhouad7cad82017-05-11 16:10:03 -0700244 }
245
gyzhoub38f3862017-07-25 16:04:31 -0700246 private void RaiseLocalVideoFrameReady(
247 IntPtr dataY, IntPtr dataU, IntPtr dataV,
248 int strideY, int strideU, int strideV,
249 uint width, uint height) {
250 if (OnLocalVideoFrameReady != null)
251 OnLocalVideoFrameReady(mPeerConnectionId, dataY, dataU, dataV, strideY, strideU, strideV,
252 width, height);
253 }
254
255 private void RaiseRemoteVideoFrameReady(
256 IntPtr dataY, IntPtr dataU, IntPtr dataV,
257 int strideY, int strideU, int strideV,
258 uint width, uint height) {
259 if (OnRemoteVideoFrameReady != null)
260 OnRemoteVideoFrameReady(mPeerConnectionId, dataY, dataU, dataV, strideY, strideU, strideV,
261 width, height);
262 }
263
264
265 private void RaiseLocalSdpReadytoSend(string type, string sdp) {
gyzhouad7cad82017-05-11 16:10:03 -0700266 if (OnLocalSdpReadytoSend != null)
gyzhoub38f3862017-07-25 16:04:31 -0700267 OnLocalSdpReadytoSend(mPeerConnectionId, type, sdp);
gyzhouad7cad82017-05-11 16:10:03 -0700268 }
269
gyzhoub38f3862017-07-25 16:04:31 -0700270 private void RaiseIceCandiateReadytoSend(string candidate, int sdpMlineIndex, string sdpMid) {
gyzhouad7cad82017-05-11 16:10:03 -0700271 if (OnIceCandiateReadytoSend != null)
gyzhoub38f3862017-07-25 16:04:31 -0700272 OnIceCandiateReadytoSend(mPeerConnectionId, candidate, sdpMlineIndex, sdpMid);
gyzhouad7cad82017-05-11 16:10:03 -0700273 }
274
gyzhoub38f3862017-07-25 16:04:31 -0700275 public void AddQueuedIceCandidate(List<IceCandidate> iceCandidateQueue) {
276 if (iceCandidateQueue != null) {
277 foreach (IceCandidate ic in iceCandidateQueue) {
278 AddIceCandidate(mPeerConnectionId, ic.Candidate, ic.SdpMlineIndex, ic.SdpMid);
279 }
280 }
281 }
282
283 private LocalDataChannelReadyInternalDelegate localDataChannelReadyDelegate = null;
gyzhouad7cad82017-05-11 16:10:03 -0700284 public event LocalDataChannelReadyDelegate OnLocalDataChannelReady;
285
gyzhoub38f3862017-07-25 16:04:31 -0700286 private DataFromDataChannelReadyInternalDelegate dataFromDataChannelReadyDelegate = null;
gyzhouad7cad82017-05-11 16:10:03 -0700287 public event DataFromDataChannelReadyDelegate OnDataFromDataChannelReady;
288
gyzhoub38f3862017-07-25 16:04:31 -0700289 private FailureMessageInternalDelegate failureMessageDelegate = null;
gyzhouad7cad82017-05-11 16:10:03 -0700290 public event FailureMessageDelegate OnFailureMessage;
291
gyzhoub38f3862017-07-25 16:04:31 -0700292 private AudioBusReadyInternalDelegate audioBusReadyDelegate = null;
gyzhouad7cad82017-05-11 16:10:03 -0700293 public event AudioBusReadyDelegate OnAudioBusReady;
294
gyzhoub38f3862017-07-25 16:04:31 -0700295 private I420FrameReadyInternalDelegate localI420FrameReadyDelegate = null;
296 public event I420FrameReadyDelegate OnLocalVideoFrameReady;
297
298 private I420FrameReadyInternalDelegate remoteI420FrameReadyDelegate = null;
299 public event I420FrameReadyDelegate OnRemoteVideoFrameReady;
300
301 private LocalSdpReadytoSendInternalDelegate localSdpReadytoSendDelegate = null;
gyzhouad7cad82017-05-11 16:10:03 -0700302 public event LocalSdpReadytoSendDelegate OnLocalSdpReadytoSend;
303
gyzhoub38f3862017-07-25 16:04:31 -0700304 private IceCandiateReadytoSendInternalDelegate iceCandiateReadytoSendDelegate = null;
gyzhouad7cad82017-05-11 16:10:03 -0700305 public event IceCandiateReadytoSendDelegate OnIceCandiateReadytoSend;
306
gyzhoub38f3862017-07-25 16:04:31 -0700307 private int mPeerConnectionId = -1;
gyzhouad7cad82017-05-11 16:10:03 -0700308 }
309}