blob: 5f26b89488c1c3b7ac9fa9b7c32eb30085af0e8d [file] [log] [blame]
qiangchen4655c742017-08-09 00:08:031This directory contains an example Unity native plugin for Windows OS and Android.
2
gyzhouacce9752017-05-11 23:10:033The 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
qiangchen4655c742017-08-09 00:08:036For detailed build instruction on Android, see ANDROID_INSTRUCTION
7
gyzhouacce9752017-05-11 23:10:038An example of wrapping native plugin into a C# managed class in Unity is given as following:
9
10using System;
gyzhou0538b612017-07-25 23:04:3111using System.Collections.Generic;
gyzhouacce9752017-05-11 23:10:0312using System.Runtime.InteropServices;
13
14namespace SimplePeerConnectionM {
gyzhou0538b612017-07-25 23:04:3115 // 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.
gyzhouacce9752017-05-11 23:10:0343 public class PeerConnectionM {
gyzhou0538b612017-07-25 23:04:3144 private const string dllPath = "webrtc_unity_plugin";
gyzhouacce9752017-05-11 23:10:0345
gyzhou0538b612017-07-25 23:04:3146 //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);
gyzhouacce9752017-05-11 23:10:0350
gyzhou0538b612017-07-25 23:04:3151 [DllImport(dllPath, CallingConvention = CallingConvention.Cdecl)]
52 private static extern bool ClosePeerConnection(int peerConnectionId);
gyzhouacce9752017-05-11 23:10:0353
gyzhou0538b612017-07-25 23:04:3154 [DllImport(dllPath, CallingConvention = CallingConvention.Cdecl)]
55 private static extern bool AddStream(int peerConnectionId, bool audioOnly);
gyzhouacce9752017-05-11 23:10:0356
gyzhou0538b612017-07-25 23:04:3157 [DllImport(dllPath, CallingConvention = CallingConvention.Cdecl)]
58 private static extern bool AddDataChannel(int peerConnectionId);
gyzhouacce9752017-05-11 23:10:0359
gyzhou0538b612017-07-25 23:04:3160 [DllImport(dllPath, CallingConvention = CallingConvention.Cdecl)]
61 private static extern bool CreateOffer(int peerConnectionId);
gyzhouacce9752017-05-11 23:10:0362
gyzhou0538b612017-07-25 23:04:3163 [DllImport(dllPath, CallingConvention = CallingConvention.Cdecl)]
64 private static extern bool CreateAnswer(int peerConnectionId);
gyzhouacce9752017-05-11 23:10:0365
gyzhou0538b612017-07-25 23:04:3166 [DllImport(dllPath, CallingConvention = CallingConvention.Cdecl)]
67 private static extern bool SendDataViaDataChannel(int peerConnectionId, string data);
gyzhouacce9752017-05-11 23:10:0368
gyzhou0538b612017-07-25 23:04:3169 [DllImport(dllPath, CallingConvention = CallingConvention.Cdecl)]
70 private static extern bool SetAudioControl(int peerConnectionId, bool isMute, bool isRecord);
gyzhouacce9752017-05-11 23:10:0371
72 [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
73 private delegate void LocalDataChannelReadyInternalDelegate();
74 public delegate void LocalDataChannelReadyDelegate(int id);
gyzhou0538b612017-07-25 23:04:3175 [DllImport(dllPath, CallingConvention = CallingConvention.Cdecl)]
76 private static extern bool RegisterOnLocalDataChannelReady(
77 int peerConnectionId, LocalDataChannelReadyInternalDelegate callback);
gyzhouacce9752017-05-11 23:10:0378
79 [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
80 private delegate void DataFromDataChannelReadyInternalDelegate(string s);
81 public delegate void DataFromDataChannelReadyDelegate(int id, string s);
gyzhou0538b612017-07-25 23:04:3182 [DllImport(dllPath, CallingConvention = CallingConvention.Cdecl)]
83 private static extern bool RegisterOnDataFromDataChannelReady(
84 int peerConnectionId, DataFromDataChannelReadyInternalDelegate callback);
gyzhouacce9752017-05-11 23:10:0385
86 [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
87 private delegate void FailureMessageInternalDelegate(string msg);
88 public delegate void FailureMessageDelegate(int id, string msg);
gyzhou0538b612017-07-25 23:04:3189 [DllImport(dllPath, CallingConvention = CallingConvention.Cdecl)]
90 private static extern bool RegisterOnFailure(int peerConnectionId,
91 FailureMessageInternalDelegate callback);
gyzhouacce9752017-05-11 23:10:0392
93 [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
gyzhou0538b612017-07-25 23:04:3194 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);
gyzhouacce9752017-05-11 23:10:03118
119 [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
gyzhou0538b612017-07-25 23:04:31120 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);
gyzhouacce9752017-05-11 23:10:03125
126 [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
gyzhou0538b612017-07-25 23:04:31127 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);
gyzhouacce9752017-05-11 23:10:03134
gyzhou0538b612017-07-25 23:04:31135 [DllImport(dllPath, CallingConvention = CallingConvention.Cdecl)]
136 private static extern bool SetRemoteDescription(int peerConnectionId, string type, string sdp);
gyzhouacce9752017-05-11 23:10:03137
gyzhou0538b612017-07-25 23:04:31138 [DllImport(dllPath, CallingConvention = CallingConvention.Cdecl)]
139 private static extern bool AddIceCandidate(int peerConnectionId, string sdp,
140 int sdpMlineindex, string sdpMid);
gyzhouacce9752017-05-11 23:10:03141
gyzhou0538b612017-07-25 23:04:31142 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);
gyzhouacce9752017-05-11 23:10:03146 RegisterCallbacks();
147 }
148
gyzhou0538b612017-07-25 23:04:31149 public void ClosePeerConnection() {
150 ClosePeerConnection(mPeerConnectionId);
151 mPeerConnectionId = -1;
gyzhouacce9752017-05-11 23:10:03152 }
153
154 // Return -1 if Peerconnection is not available.
155 public int GetUniqueId() {
gyzhou0538b612017-07-25 23:04:31156 return mPeerConnectionId;
gyzhouacce9752017-05-11 23:10:03157 }
158
gyzhou0538b612017-07-25 23:04:31159 public void AddStream(bool audioOnly) {
160 AddStream(mPeerConnectionId, audioOnly);
gyzhouacce9752017-05-11 23:10:03161 }
162
gyzhou0538b612017-07-25 23:04:31163 public void AddDataChannel() {
164 AddDataChannel(mPeerConnectionId);
gyzhouacce9752017-05-11 23:10:03165 }
166
gyzhou0538b612017-07-25 23:04:31167 public void CreateOffer() {
168 CreateOffer(mPeerConnectionId);
gyzhouacce9752017-05-11 23:10:03169 }
170
gyzhou0538b612017-07-25 23:04:31171 public void CreateAnswer() {
172 CreateAnswer(mPeerConnectionId);
gyzhouacce9752017-05-11 23:10:03173 }
174
gyzhou0538b612017-07-25 23:04:31175 public void SendDataViaDataChannel(string data) {
176 SendDataViaDataChannel(mPeerConnectionId, data);
gyzhouacce9752017-05-11 23:10:03177 }
178
gyzhou0538b612017-07-25 23:04:31179 public void SetAudioControl(bool isMute, bool isRecord) {
180 SetAudioControl(mPeerConnectionId, isMute, isRecord);
gyzhouacce9752017-05-11 23:10:03181 }
182
gyzhou0538b612017-07-25 23:04:31183 public void SetRemoteDescription(string type, string sdp) {
184 SetRemoteDescription(mPeerConnectionId, type, sdp);
gyzhouacce9752017-05-11 23:10:03185 }
186
gyzhou0538b612017-07-25 23:04:31187 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);
gyzhouacce9752017-05-11 23:10:03222 }
223
224 private void RaiseLocalDataChannelReady() {
225 if (OnLocalDataChannelReady != null)
gyzhou0538b612017-07-25 23:04:31226 OnLocalDataChannelReady(mPeerConnectionId);
gyzhouacce9752017-05-11 23:10:03227 }
228
229 private void RaiseDataFromDataChannelReady(string data) {
230 if (OnDataFromDataChannelReady != null)
gyzhou0538b612017-07-25 23:04:31231 OnDataFromDataChannelReady(mPeerConnectionId, data);
gyzhouacce9752017-05-11 23:10:03232 }
233
234 private void RaiseFailureMessage(string msg) {
235 if (OnFailureMessage != null)
gyzhou0538b612017-07-25 23:04:31236 OnFailureMessage(mPeerConnectionId, msg);
gyzhouacce9752017-05-11 23:10:03237 }
238
gyzhou0538b612017-07-25 23:04:31239 private void RaiseAudioBusReady(IntPtr data, int bitsPerSample,
240 int sampleRate, int numberOfChannels, int numberOfFrames) {
gyzhouacce9752017-05-11 23:10:03241 if (OnAudioBusReady != null)
gyzhou0538b612017-07-25 23:04:31242 OnAudioBusReady(mPeerConnectionId, data, bitsPerSample, sampleRate,
243 numberOfChannels, numberOfFrames);
gyzhouacce9752017-05-11 23:10:03244 }
245
gyzhou0538b612017-07-25 23:04:31246 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) {
gyzhouacce9752017-05-11 23:10:03266 if (OnLocalSdpReadytoSend != null)
gyzhou0538b612017-07-25 23:04:31267 OnLocalSdpReadytoSend(mPeerConnectionId, type, sdp);
gyzhouacce9752017-05-11 23:10:03268 }
269
gyzhou0538b612017-07-25 23:04:31270 private void RaiseIceCandiateReadytoSend(string candidate, int sdpMlineIndex, string sdpMid) {
gyzhouacce9752017-05-11 23:10:03271 if (OnIceCandiateReadytoSend != null)
gyzhou0538b612017-07-25 23:04:31272 OnIceCandiateReadytoSend(mPeerConnectionId, candidate, sdpMlineIndex, sdpMid);
gyzhouacce9752017-05-11 23:10:03273 }
274
gyzhou0538b612017-07-25 23:04:31275 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;
gyzhouacce9752017-05-11 23:10:03284 public event LocalDataChannelReadyDelegate OnLocalDataChannelReady;
285
gyzhou0538b612017-07-25 23:04:31286 private DataFromDataChannelReadyInternalDelegate dataFromDataChannelReadyDelegate = null;
gyzhouacce9752017-05-11 23:10:03287 public event DataFromDataChannelReadyDelegate OnDataFromDataChannelReady;
288
gyzhou0538b612017-07-25 23:04:31289 private FailureMessageInternalDelegate failureMessageDelegate = null;
gyzhouacce9752017-05-11 23:10:03290 public event FailureMessageDelegate OnFailureMessage;
291
gyzhou0538b612017-07-25 23:04:31292 private AudioBusReadyInternalDelegate audioBusReadyDelegate = null;
gyzhouacce9752017-05-11 23:10:03293 public event AudioBusReadyDelegate OnAudioBusReady;
294
gyzhou0538b612017-07-25 23:04:31295 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;
gyzhouacce9752017-05-11 23:10:03302 public event LocalSdpReadytoSendDelegate OnLocalSdpReadytoSend;
303
gyzhou0538b612017-07-25 23:04:31304 private IceCandiateReadytoSendInternalDelegate iceCandiateReadytoSendDelegate = null;
gyzhouacce9752017-05-11 23:10:03305 public event IceCandiateReadytoSendDelegate OnIceCandiateReadytoSend;
306
gyzhou0538b612017-07-25 23:04:31307 private int mPeerConnectionId = -1;
gyzhouacce9752017-05-11 23:10:03308 }
309}