You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
310 lines
13 KiB
310 lines
13 KiB
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;
|
|
}
|
|
}
|