webrtc/examples/unityplugin
Magnus Jedvert 1a759c6354 Android: Only use Java VideoFrames internally
This CL removes internal support for anything else than Android frames
that are wrapped Java VideoFrames. This allows for a big internal
cleanup and we can remove the internal class AndroidTextureBuffer and
all logic related to that. Also, the C++ AndroidVideoTrackSource no
longer needs to hold on to a C++ SurfaceTextureHelper and we can
remove all JNI code related to SurfaceTextureHelper. Also, when these
methods are removed, it's possible to let VideoSource implement the
CapturerObserver interface directly and there is no longer any need for
AndroidVideoTrackSourceObserver. Clients can then initialize
VideoCapturers themselves outside the PeerConnectionFactory, and a new
method is added in the PeerConnectionFactory to allow clients to create
standalone VideoSources that can be connected to a VideoCapturer outside
the factory.

Bug: webrtc:9181
Change-Id: Ie292ea9214f382d44dce9120725c62602a646ed8
Reviewed-on: https://webrtc-review.googlesource.com/71666
Commit-Queue: Magnus Jedvert <magjed@webrtc.org>
Reviewed-by: Sami Kalliomäki <sakal@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#23004}
2018-04-24 13:51:11 +00:00
..
java/src/org/webrtc Android: Only use Java VideoFrames internally 2018-04-24 13:51:11 +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 Android: Only use Java VideoFrames internally 2018-04-24 13:51:11 +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;
  }
}