WebRTC Video Chat

作者:追风剑情 发布于:2023-12-13 11:28 分类:Unity3d

WebRTC Video Chat

Unity跨平台视频通话插件WebRtcVideoChat,可实现PC、Android、IOS跨平台的视频通话,可语音、视频以及发送文字。
[百度网盘] WebRTC Video Chat 0.9854.unitypackage 提取码 ijys

[GitHub] WebRTC Signaling Server

如果想生成APK测试demo,需要将所有场景加入列表
111111.png

注意:在Android平台上创建两个网络对象会报错 Channel is unrecoverably broken and will be disposed! 导致闪退。

注意:4G/5G网络无法建立P2P

视频画面需要逆时针旋转90度再显示,下面是利用Shader旋转uv

fixed4 frag(v2f i) : SV_Target
{
	//逆时针旋转90度
	fixed2 uv = fixed2(i.uv.y, i.uv.x);
	fixed4 col = tex2D(_MainTex, uv);
	return col;
}

YUV与RGB相互转换公式


WebRTC辅助类

using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using UnityEngine;
using Byn.Awrtc;
using Byn.Awrtc.Unity;
/// <summary>
/// WebRtcVideoChat 辅助类
/// 同一个网络对象上只能创建一个房间,但可以加入多个房间
/// 注意:Android平台上不能同时创建多个网络对象(Network),会报错闪退。
/// </summary>
public sealed class WebRTCHelper
{
    #region 变量
    //信令服务器地址 (这是官方的测试地址)
    public static string uSignalingUrl = "ws://signaling.because-why-not.com/chatapp";
    //信令服务器地址,基于WebGL的浏览器用这个地址 (这是官方的测试地址)
    public static string uSecureSignalingUrl = "wss://signaling.because-why-not.com/chatapp";
    //true: 强制使用 uSecureSignalingUrl
    public static bool uForceSecureSignaling = false;

    //NAT穿透服务器地址, Stun server。(这是官方的测试地址)
    public static readonly string stunUrl = "stun:stun.because-why-not.com:443";
    //NAT穿透服务器地址, Turn server。(这是官方的测试地址)
    public static readonly string turnUrl = "turn:turn.because-why-not.com:443";
    //Turn server user
    public static readonly string turnUser = "testuser140";
    //Turn server password
    public static readonly string turnPass = "pass140";
    //NAT穿透服务器地址 (Turn server 或 Stun server)
    public static string uIceServer = turnUrl;
    //备用服务器
    public static string uIceServer2 = "stun:stun.l.google.com:19302";
    public static string uIceServerUser = turnUser;
    public static string uIceServerPassword = turnPass;
    //可以是 native webrtc 或 browser webrtc
    //BasicNetwork用于收发自定义数据
    private static IBasicNetwork mBasicNetwork = null;
    //谁开房间,谁就作为服务器方
    private static bool mIsServer = false;
    //房间名允许的最长字符个数,不要使用中文
    private const int MAX_CODE_LENGTH = 256;
    //连接ID列表
    private static List<ConnectionId> mConnections = new List<ConnectionId>();
    //用于音/视频聊天的对象
    private static ICall mCall;
    //true: 每次本地视频设备创建新帧时,FrameUpdateEventArgs都会更新
    private static bool mLocalFrameEvents = true;
    private static ConnectionId mRemoteUserId;
    private static MediaConfig mMediaConfig;
    private static MediaConfig mMediaConfigInUse;

    public static Action<string> OnTextHandler;
    public static Action<string> OnLogHandler;
    public static Action<FrameUpdateEventArgs> OnVideoFrameUpdate;

    //信令协议
    public static string SignalingProtocol
    {
        get
        {

            string protocol = "ws";
            if (Application.platform == RuntimePlatform.WebGLPlayer)
            {
                protocol = "wss";
            }
            return protocol;
        }
    }
    #endregion

    #region 初始化
    /// <summary>
    /// 初始WebRTC
    /// </summary>
    /// <param name="initBasicNetwork">初始化基本网络对象用于:收发消息</param>
    /// <param name="initCall">初始化Call对象用于:收发消息、音/视频通话</param>
    public static void Init(bool initBasicNetwork=true, bool initCall=true)
    {
        InitFactory();
        if (initBasicNetwork)
            InitBasicNetwork();
        if (initCall)
            InitCall();
    }
    #endregion

    #region Factory
    //初始化 WebRtc Network Factory
    private static void InitFactory()
    {
        Debug.Log("Initializing webrtc factory");
        UnityCallFactory.EnsureInit(OnCallFactoryReady, OnCallFactoryFailed);
    }

    private static void OnCallFactoryReady()
    {
        Debug.Log("WebRtcNetworkFactory created");
        UnityCallFactory.Instance.RequestLogLevel(UnityCallFactory.LogLevel.Info);
    }

    private static void OnCallFactoryFailed(string error)
    {
        string fullErrorMsg = "The " + typeof(UnityCallFactory).Name + " failed to initialize with following error: " + error;
        Debug.LogError(fullErrorMsg);
    }
    #endregion

    #region 基本网络
    //初始化 WebRTC BasicNetwork
    private static void InitBasicNetwork()
    {
        if (mBasicNetwork != null)
            return;

        Debug.Log("Initializing webrtc network");
        string signalingUrl = uSignalingUrl;

        if (Application.platform == RuntimePlatform.WebGLPlayer || uForceSecureSignaling)
        {
            signalingUrl = uSecureSignalingUrl;
        }

        List<IceServer> iceServers = new List<IceServer>();
        if (string.IsNullOrEmpty(uIceServer) == false)
            iceServers.Add(new IceServer(uIceServer, uIceServerUser, uIceServerPassword));

        if (string.IsNullOrEmpty(uIceServer2) == false)
            iceServers.Add(new IceServer(uIceServer2));

        if (string.IsNullOrEmpty(signalingUrl))
        {
            throw new InvalidOperationException("set signaling url is null or empty");
        }

        mBasicNetwork = UnityCallFactory.Instance.CreateBasicNetwork(signalingUrl, iceServers.ToArray());
        if (mBasicNetwork != null)
        {
            Debug.Log("WebRTCNetwork created");
        }
        else
        {
            Debug.Log("Failed to access webrtc ");
        }
    }

    /// <summary>
    /// 断开某个连接
    /// </summary>
    /// <param name="id">连接ID</param>
    public static void Disconnect(ConnectionId id)
    {
        if (mBasicNetwork == null)
            return;
        mBasicNetwork.Disconnect(id);
    }

    /// <summary>
    /// 断开所有连接
    /// </summary>
    public static void DisconnectAll()
    {
        if (mBasicNetwork == null)
            return;
        mBasicNetwork.Dispose();
    }

    //检查网络事件,需在FixedUpdate()中调用此方法
    public static void HandleNetwork()
    {
        if (mBasicNetwork == null)
            return;
        //从底层读取数据
        mBasicNetwork.Update();
        //处理自上次更新以来发生的所有新事件
        NetworkEvent evt;
        //检查每个事件
        while (mBasicNetwork != null && mBasicNetwork.Dequeue(out evt))
        {
            Debug.LogFormat("Handler Network Event: {0}", evt);
            switch (evt.Type)
            {
                //服务器初始化完成
                case NetEventType.ServerInitialized:
                    mIsServer = true;
                    string address = evt.Info;
                    Debug.Log("Server started. Address: " + address);
                    break;
                //启动服务器失败,可能是信令服务器关闭了
                case NetEventType.ServerInitFailed:
                    mIsServer = false;
                    Debug.Log("Server start failed." + evt.Info);
                    Dispose();
                    break;
                //服务器关闭
                case NetEventType.ServerClosed:
                    mIsServer = false;
                    Debug.LogFormat("Server closed. {0}", evt.Info);
                    break;
                //用户运行客户端并连接到服务器
                //用户运行该服务器,并连接了一个新的客户端
                case NetEventType.NewConnection:
                    mConnections.Add(evt.ConnectionId);
                    Debug.Log("New local connection! ID: " + evt.ConnectionId);
                    //如果是服务器,请向所有人发送公告,并使用本地Id作为用户名
                    if (mIsServer)
                    {
                        //用户运行一个服务器, 向大家宣布新的连接.
                        //使用服务器端连接ID作为标识
                        string msg = "New user " + evt.ConnectionId + " joined the room.";
                        Debug.Log(msg);
                        SendString(msg);
                    }
                    break;
                //服务器收到失败连接
                //与服务器建立连接失败
                case NetEventType.ConnectionFailed:
                    if (mIsServer)
                    {
                        //收到一个失败连接
                        //原因: 收到了连接请求,但信令传送失败。
                        //1.防火墙阻止了直接连接,但允许信号启动连接过程(可能是本地防火墙,也可能是远端防火墙)
                        //2.STUN/TURN 服务器未启动
                        //3.用户在连接完全建立之前就切断了连接
                        Debug.Log("An incoming connection failed.");
                    }
                    else
                    {
                        //与服务器建立连接失败
                        Debug.Log("Connection failed. " + evt.Info);
                        Dispose();
                    }
                    break;
                //连接中断
                case NetEventType.Disconnected:
                    mConnections.Remove(evt.ConnectionId);
                    Debug.Log("Local Connection ID " + evt.ConnectionId + " disconnected");
                    if (mIsServer)
                    {
                        string userLeftMsg = "User " + evt.ConnectionId + " left the room.";
                        Debug.Log(userLeftMsg);
                        //通过其他客户端,有玩家离线
                        if (mConnections.Count > 0)
                        {
                            SendString(userLeftMsg);
                        }
                    }
                    else
                    {
                        Dispose();
                    }
                    break;
                //收到可靠消息
                case NetEventType.ReliableMessageReceived:
                //收到不可靠消息
                case NetEventType.UnreliableMessageReceived:
                    HandleIncommingMessage(ref evt);
                    break;
            }
        }
        //如果更新期间网络未中断,请刷新消息以完成此更新
        if (mBasicNetwork != null)
            mBasicNetwork.Flush();
    }

    //处理收到的消息
    private static void HandleIncommingMessage(ref NetworkEvent evt)
    {
        MessageDataBuffer buffer = (MessageDataBuffer)evt.MessageData;
        string msg = Encoding.UTF8.GetString(buffer.Buffer, 0, buffer.ContentLength);
        OnTextHandler?.Invoke(msg);
        //如果服务器将消息转发给包括发件人在内的所有其他人
        if (mIsServer)
        {
            //我们使用服务器端连接id来标识客户端
            string idAndMessage = evt.ConnectionId + ":" + msg;
            Debug.Log(idAndMessage);
            //SendString(idAndMessage);
        }
        else
        {
            //客户端收到服务器发来的消息
            Debug.Log(msg);
        }
        //返回缓冲区,以便网络可以重用它
        buffer.Dispose();
    }

    //发送消息
    public static void SendString(string msg, bool reliable = true)
    {
        if (mBasicNetwork != null)
        {
            byte[] msgData = Encoding.UTF8.GetBytes(msg);
            foreach (ConnectionId id in mConnections)
            {
                mBasicNetwork.SendData(id, msgData, 0, msgData.Length, reliable);
            }
        }
        else if (mCall != null)
        {
            mCall.Send(msg, reliable);
        }
    }

    /// <summary>
    /// 创建房间 (仅支持文本聊天)
    /// </summary>
    /// <param name="roomName">房间名称(不能超过256个字符)</param>
    public static void OpenChatRoom(string roomName)
    {
        InitBasicNetwork();
        roomName = EnsureLength(roomName);
        //如果该地址正在使用中,则底层系统将返回服务器连接失败
        mBasicNetwork.StartServer(roomName);
        Debug.Log("Open Room " + roomName);
    }

    /// <summary>
    /// 关闭房间
    /// 房间关闭后,将不再接受新用户的连接,但不影响现有已建立连接的用户
    /// 当房间达到预设的最大人数后,可以调用此方法
    /// </summary>
    public static void CloseChatRoom()
    {
        if (mBasicNetwork == null)
            return;
        mBasicNetwork.StopServer();
        Debug.Log("Close Room");
    }

    /// <summary>
    /// 加入房间,可以同时加入不同的房间
    /// </summary>
    /// <param name="roomName">房间名称(不能超过256个字符)</param>
    public static void JoinChatRoom(string roomName)
    {
        InitBasicNetwork();
        roomName = EnsureLength(roomName);
        mBasicNetwork.Connect(roomName);
        Debug.Log("Join Room " + roomName + " ...");
    }

    //确保房间名称长度不超过256
    private static string EnsureLength(string roomName)
    {
        if (roomName.Length > MAX_CODE_LENGTH)
        {
            roomName = roomName.Substring(0, MAX_CODE_LENGTH);
        }
        return roomName;
    }
    #endregion

    #region 视频聊天
    //初始化Call, 音/视频聊天需要调用这个方法
    private static void InitCall()
    {
        if (mCall != null)
            return;
        NetworkConfig config = CreateNetworkConfig();
        mCall = CreateCall(config);
        if (mCall == null)
        {
            Debug.Log("Failed to create the call");
            return;
        }
        mCall.LocalFrameEvents = mLocalFrameEvents;
        mCall.CallEvent += OnCallEvent;

        if (mMediaConfig == null)
            mMediaConfig = CreateMediaConfig();
        mMediaConfigInUse = mMediaConfig.DeepClone();

        //如果没有配置摄像头设备名称,则自动设置为前置摄像头
        if (mMediaConfigInUse.Video && string.IsNullOrEmpty(mMediaConfigInUse.VideoDeviceName))
        {
            string[] devices = UnityCallFactory.Instance.GetVideoDevices();
            if (devices == null || devices.Length == 0)
            {
                Debug.Log("no device found or no device information available");
            }
            else
            {
                foreach (string s in devices)
                    Debug.Log("device found: " + s + " IsFrontFacing: " + UnityCallFactory.Instance.IsFrontFacing(s));
            }
            mMediaConfigInUse.VideoDeviceName = UnityCallFactory.Instance.GetDefaultVideoDevice();
        }

        Debug.Log("Configure call using MediaConfig: " + mMediaConfigInUse);
        //设置配置
        mCall.Configure(mMediaConfigInUse);
    }

    //创建网络配置
    private static NetworkConfig CreateNetworkConfig()
    {
        NetworkConfig netConfig = new NetworkConfig();
        if (string.IsNullOrEmpty(uIceServer) == false)
            netConfig.IceServers.Add(new IceServer(uIceServer, uIceServerUser, uIceServerPassword));
        if (string.IsNullOrEmpty(uIceServer2) == false)
            netConfig.IceServers.Add(new IceServer(uIceServer2));

        if (Application.platform == RuntimePlatform.WebGLPlayer || uForceSecureSignaling)
        {
            netConfig.SignalingUrl = uSecureSignalingUrl;
        }
        else
        {
            netConfig.SignalingUrl = uSignalingUrl;
        }

        if (netConfig.SignalingUrl == "")
        {
            throw new InvalidOperationException("set signaling url is empty");
        }
        return netConfig;
    }

    //创建Call对象
    private static ICall CreateCall(NetworkConfig netConfig)
    {
        return UnityCallFactory.Instance.Create(netConfig);
    }

    //创建媒体配置
    public static MediaConfig CreateMediaConfig()
    {
        MediaConfig mediaConfig = new MediaConfig();
        //是否消除回音 (native only)
        bool useEchoCancellation = true;
        if (useEchoCancellation)
        {
#if (!UNITY_WEBGL && !UNITY_WSA)
            var nativeConfig = new Byn.Awrtc.Native.NativeMediaConfig();
            nativeConfig.AudioOptions.echo_cancellation = true;

            mediaConfig = nativeConfig;
#endif
        }

#if UNITY_WSA && !UNITY_EDITOR
        var uwpConfig = new Byn.Awrtc.Uwp.UwpMediaConfig();
        uwpConfig.Mrc = true;
        //uwpConfig.ProcessLocalFrames = false;
        //uwpConfig.DefaultCodec = "H264";
        mediaConfig = uwpConfig;
        Debug.Log("Using uwp specific media config: " + mediaConfig);
#endif
        //开启音频
        mediaConfig.Audio = true;
        //开启视频
        mediaConfig.Video = true;
        mediaConfig.VideoDeviceName = null;
        //图像格式
        mediaConfig.Format = FramePixelFormat.ABGR;
        //最小分辨率
        mediaConfig.MinWidth = 160;
        mediaConfig.MinHeight = 120;
        //分辨率越大编码/解码越慢
        mediaConfig.MaxWidth = 1920 * 2;
        mediaConfig.MaxHeight = 1080 * 2;
        //WebRTC会优先考虑IdealWidth、IdealHeight、IdealFrameRate
        //理想分辨率、帧率
        mediaConfig.IdealWidth = 160;
        mediaConfig.IdealHeight = 120;
        mediaConfig.IdealFrameRate = 30;

        return mediaConfig;
    }

    //创建视频聊天房间
    public static void OpenCallRoom(string roomName)
    {
        InitCall();
        mCall.Listen(roomName);
    }

    //加入视频聊天房间
    public static void JoinCallRoom(string roomName)
    {
        InitCall();
        //不要在会议模式下使用Call接口
        mCall.Call(roomName);
    }

    //是否设置成了静音
    public static bool IsMute()
    {
        if (mCall == null)
            return true;
        return mCall.IsMute();
    }

    //设置静音
    public static void SetMute(bool val)
    {
        if (mCall == null)
            return;
        mCall.SetMute(val);
    }

    //检查手机扬声器是否已打开。仅适用于移动本地平台
    public static bool GetLoudspeakerStatus()
    {
        if (mCall != null)
        {
            return UnityCallFactory.Instance.GetLoudspeakerStatus();
        }
        return false;
    }

    //打开/关闭手机扬声器。仅适用于移动本地平台
    public static void SetLoudspeakerStatus(bool state)
    {
        if (mCall != null)
        {
            UnityCallFactory.Instance.SetLoudspeakerStatus(state);
        }
    }

    //设置是否显示本地视频
    //如果不需要显示本地摄像头画面,可以设置成false
    public static void SetShowLocalVideo(bool showLocalVideo)
    {
        mLocalFrameEvents = showLocalVideo;
    }

    //视频聊天驱动方法,需要每帧调用
    public static void CallUpdate()
    {
        if (mCall == null)
            return;
        //将底层事件转发到Unity线程中
        mCall.Update();
    }

    //处理Call事件
    private static void OnCallEvent(object sender, CallEventArgs e)
    {
        Debug.Log(e.Type);
        switch (e.Type)
        {
            //呼出电话成功或来电到达
            case CallEventType.CallAccepted:
                {
                    //HasAudioTrack() 判断对方麦克风是否可用
                    //HasVideoTrack() 判断对方摄像头是否可用
                    mRemoteUserId = ((CallAcceptedEventArgs)e).ConnectionId;
                    string msg = "New connection with id: " + mRemoteUserId
                        + " audio:" + mCall.HasAudioTrack(mRemoteUserId)
                        + " video:" + mCall.HasVideoTrack(mRemoteUserId);
                    Debug.Log(msg);
                    OnLogHandler?.Invoke(msg);
                    mConnections.Add(mRemoteUserId);
                }
                break;
            //通话结束或其中一个用户挂断电话
            case CallEventType.CallEnded:
                CleanupCall();
                break;
            //来电失败
            case CallEventType.ListeningFailed:
                {
                    ErrorEventArgs args = e as ErrorEventArgs;
                    string msg = "ListeningFailed: " + args.Info;
                    Debug.Log(msg);
                    OnLogHandler?.Invoke(msg);
                }
                break;
            //连接房间失败
            case CallEventType.ConnectionFailed:
                {
                    ErrorEventArgs args = e as ErrorEventArgs;
                    string msg = "ConnectionFailed: " + args.Info;
                    Debug.Log(msg);
                    OnLogHandler?.Invoke(msg);
                    CleanupCall();
                }
                break;
            //当前系统不支持摄像头或麦克风,或不支持请求的分辨率,或权限不足
            case CallEventType.ConfigurationFailed:
                {
                    ErrorEventArgs args = e as ErrorEventArgs;
                    string msg = "ConfigurationFailed: " + args.Info;
                    Debug.Log(msg);
                    OnLogHandler?.Invoke(msg);
                    CleanupCall();
                }
                break;
            //收到一个新的视频帧(来自于本地摄像头或网络)
            case CallEventType.FrameUpdate:
                if (e is FrameUpdateEventArgs)
                {
                    var evt = e as FrameUpdateEventArgs;
                    OnVideoFrameUpdate?.Invoke(evt);
                }
                break;
            //收到文本消息
            case CallEventType.Message:
                {
                    MessageEventArgs args = e as MessageEventArgs;
                    Debug.Log(args.Content);
                    OnTextHandler?.Invoke(args.Content);
                }
                break;
            //接到来电
            case CallEventType.WaitForIncomingCall:
                {
                    //聊天应用程序将等待另一个应用程序通过相同的字符串连接
                    WaitForIncomingCallEventArgs args = e as WaitForIncomingCallEventArgs;
                    string msg = "WaitForIncomingCall: " + args.Address;
                    Debug.Log(msg);
                    OnLogHandler?.Invoke(msg);
                }
                break;
        }
    }

    //清理Call
    public static void CleanupCall()
    {
        if (mCall == null)
            return;
        mCall.CallEvent -= OnCallEvent;
        mCall.Dispose();
        mCall = null;
        mRemoteUserId = ConnectionId.INVALID;
        mConnections.Clear();
        GC.Collect();
        GC.WaitForPendingFinalizers();
        Debug.Log("Call destroyed");
    }

    //请求权限
    public static IEnumerator RequestPermissions(bool audio = true, bool video = true)
    {
        if (audio)
        {
            yield return RequestAudioPermission();
        }
        if (video)
        {
            yield return RequestVideoPermission();
        }

        yield return null;

    }

    //请求麦克风权限
    public static IEnumerator RequestAudioPermission()
    {
#if UNITY_ANDROID && UNITY_2018_3_OR_NEWER
        if (!HasAudioPermission())
        {
            Debug.Log("Requesting microphone permissions");
            UnityEngine.Android.Permission.RequestUserPermission(UnityEngine.Android.Permission.Microphone);
            //同一帧中连续调用两次请求会导致请求被忽略
            //等待用户按下 "允许" 或 "拒绝"
            yield return new WaitForSeconds(0.1f);
            //极少数情况下即使用户选择"允许",也可能返回false
            Debug.Log("microphone permission: " + HasAudioPermission());
        }
#endif
        yield return null;
    }

    //请求摄像头权限
    public static IEnumerator RequestVideoPermission()
    {
#if UNITY_ANDROID && UNITY_2018_3_OR_NEWER
        if (!HasVideoPermission())
        {
            Debug.Log("Requesting camera permissions");
            UnityEngine.Android.Permission.RequestUserPermission(UnityEngine.Android.Permission.Camera);
            yield return new WaitForSeconds(0.1f);
            Debug.Log("camera permission: " + HasVideoPermission());
        }
#endif
        yield return null;
    }

    //是否有使用麦克风的权限
    public static bool HasAudioPermission()
    {
#if UNITY_ANDROID && UNITY_2018_3_OR_NEWER
        if (Application.platform == RuntimePlatform.Android)
        {
            return UnityEngine.Android.Permission.HasUserAuthorizedPermission(UnityEngine.Android.Permission.Microphone);
        }
#endif
        return true;
    }

    //是否有使用摄像头的权限
    public static bool HasVideoPermission()
    {
#if UNITY_ANDROID && UNITY_2018_3_OR_NEWER
        if (Application.platform == RuntimePlatform.Android)
        {
            return UnityEngine.Android.Permission.HasUserAuthorizedPermission(UnityEngine.Android.Permission.Camera);
        }
#endif
        return true;
    }
    #endregion

    #region 释放资源
    //释放
    public static void Dispose()
    {
        if (mBasicNetwork != null)
        {
            mBasicNetwork.Dispose();
            mBasicNetwork = null;
        }
        mConnections.Clear();
        mIsServer = false;
        CleanupCall();
    }
    #endregion
}


视频通话测试

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using Byn.Awrtc;
using Byn.Awrtc.Unity;
/// <summary>
/// 视频通话测试
/// </summary>
public class CallTest : MonoBehaviour
{
    [SerializeField]
    private InputField roomNameInput;
    [SerializeField]
    private InputField messageInput;
    [SerializeField]
    private Text msgText;
    [SerializeField]
    private Text logText;
    [SerializeField]
    private RawImage localVideoImage;
    private Texture2D localTexture;
    [SerializeField]
    private RawImage remoteVideoImage;
    private Texture2D remoteTexture;

    void Start()
    {
        //请求权限
        StartCoroutine(WebRTCHelper.RequestPermissions());
        //初始化
        WebRTCHelper.Init(false, true);
        WebRTCHelper.OnTextHandler = OnTextHandler;
        WebRTCHelper.OnLogHandler = OnLogHandler;
        WebRTCHelper.OnVideoFrameUpdate = OnVideoFrameUpdate;
    }

    private void OnDestroy()
    {
        WebRTCHelper.Dispose();
    }

    void Update()
    {
        WebRTCHelper.CallUpdate();
    }

    private void FixedUpdate()
    {
        WebRTCHelper.HandleNetwork();
    }

    public void OnClickOpenChatRoom()
    {
        WebRTCHelper.OpenChatRoom(roomNameInput.text);
    }

    public void OnClickJoinChatRoom()
    {
        WebRTCHelper.JoinChatRoom(roomNameInput.text);
    }

    public void OnClickOpenCallRoom()
    {
        WebRTCHelper.OpenCallRoom(roomNameInput.text);
    }

    public void OnClickJoinCallRoom()
    {
        WebRTCHelper.JoinCallRoom(roomNameInput.text);
    }

    public void OnClickSend()
    {
        WebRTCHelper.SendString(messageInput.text);
    }

    public void OnClickHungup()
    {
        WebRTCHelper.CleanupCall();
    }

    //处理收到的文本消息
    private void OnTextHandler(string msg)
    {
        msgText.text = msg;
    }

    //处理收到的错误消息
    private void OnLogHandler(string error)
    {
        logText.text = error;
    }

    //处理收到的视频帧
    private void OnVideoFrameUpdate(FrameUpdateEventArgs e)
    {
        if (e.IsRemote)
        {
            UpdateRemoteTexture(e.Frame);
        }
        else
        {
            UpdateLocalTexture(e.Frame);
        }
    }

    //更新本地视频画面
    private void UpdateLocalTexture(IFrame frame)
    {
        if (frame == null)
            return;
        //UnityMediaHelper.UpdateRawImage(localVideoImage, frame);
        if (localTexture == null)
            localTexture = new Texture2D(frame.Width, frame.Height, TextureFormat.RGBA32, false);
        UnityMediaHelper.UpdateTexture(frame, ref localTexture);
        if (localVideoImage.texture == null)
            localVideoImage.texture = localTexture;
    }

    //更新远程视频画面
    private void UpdateRemoteTexture(IFrame frame)
    {
        if (frame == null)
            return;
        //UnityMediaHelper.UpdateRawImage(remoteVideoImage, frame);
        if (remoteTexture == null)
            remoteTexture = new Texture2D(frame.Width, frame.Height, TextureFormat.RGBA32, false);
        UnityMediaHelper.UpdateTexture(frame, ref remoteTexture);
        if (remoteVideoImage.texture == null)
            remoteVideoImage.texture = remoteTexture;
    }
}

标签: Unity3d

Powered by emlog  蜀ICP备18021003号-1   sitemap

川公网安备 51019002001593号