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

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;
}
}