webrtc/examples/unityplugin
Seth Hampson 13b8bad235 Final name changing of MediaStreamInterface.label() to id().
Downstreams have been updated, and this now updates all uses of label()
to id() within WebRTC code. This change also makes id() pure virtual and
removes label().

Bug: webrtc:8977
Change-Id: Ib045ea4fabba6f14447c64875c7aeba87dc2be24
Reviewed-on: https://webrtc-review.googlesource.com/60382
Reviewed-by: Per Kjellander <perkj@webrtc.org>
Reviewed-by: Taylor Brandstetter <deadbeef@webrtc.org>
Commit-Queue: Seth Hampson <shampson@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#22431}
2018-03-14 20:30:52 +00:00
..
java/src/org/webrtc Synced webrtc_unity_plugin to the latest webrtc and fixed bugs. 2018-03-09 18:34:14 +00:00
ANDROID_INSTRUCTION Synced webrtc_unity_plugin to the latest webrtc and fixed bugs. 2018-03-09 18:34:14 +00:00
classreferenceholder.cc Fixing WebRTC after moving from src/webrtc to src/ 2017-09-15 05:02:56 +00:00
classreferenceholder.h Fixing WebRTC after moving from src/webrtc to src/ 2017-09-15 05:02:56 +00:00
DEPS Synced webrtc_unity_plugin to the latest webrtc and fixed bugs. 2018-03-09 18:34:14 +00:00
jni_onload.cc Fixing WebRTC after moving from src/webrtc to src/ 2017-09-15 05:02:56 +00:00
OWNERS Reland: Add Alpha Channel Support For WebRTC Unity Plugin 2017-12-20 21:56:17 +00:00
README Moving src/webrtc into src/. 2017-09-15 04:25:06 +00:00
simple_peer_connection.cc Final name changing of MediaStreamInterface.label() to id(). 2018-03-14 20:30:52 +00:00
simple_peer_connection.h Bug Fix: WebRTC Unity Plugin Audio One Way 2017-12-05 20:36:12 +00:00
unity_plugin_apis.cc Reland: Add Alpha Channel Support For WebRTC Unity Plugin 2017-12-20 21:56:17 +00:00
unity_plugin_apis.h Reland: Add Alpha Channel Support For WebRTC Unity Plugin 2017-12-20 21:56:17 +00:00
video_observer.cc Reland: Add Alpha Channel Support For WebRTC Unity Plugin 2017-12-20 21:56:17 +00:00
video_observer.h Move videosinkinterface.h to common_video to solve a circular dep. 2018-01-04 13:19:49 +00:00

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