有没有办法使用 Photon Pun2 或 Photon Chat 发送或接收图像、音频和视频?

Posted

技术标签:

【中文标题】有没有办法使用 Photon Pun2 或 Photon Chat 发送或接收图像、音频和视频?【英文标题】:Is there any way to send or receive images, audio and video using Photon Pun2 or Photon Chat? 【发布时间】:2021-05-17 20:33:28 【问题描述】:

我在我的应用程序中同时使用了 Photon Pun2 和 Photon Chat 软件包。但是我找不到任何通过私信发送或接收图像、音频或视频的方法。

【问题讨论】:

【参考方案1】:

是的……但是,它非常有限。

你要寄的东西到底有多大?


聊天

在 Photon 聊天消息中,有效负载限制在 400.000 到 500.000 字节之间。我没有更详细地对其进行测试,但是如果您的消息大小达到某个限制,您将立即断开连接而没有适当的反馈,原因是^^

见Photon Chat Intro

例子

public class MyChatListner : IChatClientListener

    public event Action<byte[]> OnReceived;

    private ChatClient cient;

    public void Initialize()
    
        client = new ChatClient(this);
        
        client.ChatRegion = ...;
        client.Connect(....);
    
 
    // Sicne you already work with the chat you should know but anyway
    // This has to be called continuously (who knows in what intervals)
    public void Heartbeat()
    
        client.Service();
    

    public void SendData(string recipient, byte[] data)
    
        client.SendPrivateMessage(recipient, data);
    

    public void OnPrivateMessage(string sender, object message, string channelName)
    
        OnReceived?.Invoke((byte[])message);
    
    
    // also will have to implement the other methods from IChatClientListener ...


PUN2

在 Pun2 中,我不知道是否存在这样的限制,但它肯定会延迟其他一切,直到文件完全接收。这里可以直接通过PhotonNetwork.RaiseEventOnEvent收发byte[](通过接口IOnEventCallback

例子

// doesn't even have to be monobehaviour necessarily
public class FileTransmitter : IOnEventCallback

    private const byte eventID = 42;

    public event Action<byte[]> OnReceived;

    public void Enable()
    
        PhotonNetwork.AddCallbackTarget(this);
    

    public void Disable()
    
        PhotonNetwork.RemoveCallbackTarget(this);
    

    public void SendData(byte[] data, SendOptions sendoptions, RaiseEventOptions raiseEventOptions = null)
    
        PhotonNetwork.RaiseEvent(eventID, data, raiseEventOptions, sendoptions);
    

    public void OnEvent(EventData photonEvent)
    
        if(photonEvent.Code != eventID) return;

        var data = (byte[]) photonEvent.CustomData;

        OnReceived?.Invoke(data);
    

当然,您也可以直接使用RPC 并使用例如

public class FileTransfer : MonoBehaviourPun

    [PunRPC]
    void ChatMessage(string fileName, byte[] content)
    
        // e.g.
        File.WriteAllBytes(Path.Combine(Application.persistentDataPath, fileName), content);
    

    public void SendFile(string fileName, byte[] content, PhotonPlayer targetPlayer)
    
        photonView.RPC(nameof(ChatMessage), targetPlayer, fileName, content);
    

无论哪种方式,我个人所做的只是使用一个byte[] 并将所有必需的信息编码到其中。 Photon 无论如何都会使用所有参数执行此操作,但如果您已经确切知道您发送的数据以及如何反序列化它,那么您自己执行此操作会更有效,例如在线程/任务中。然后在接收方我再次将这些反序列化为个人信息。

【讨论】:

【参考方案2】:

这是可能的并且工作得很好(即使你应该注意@derHugo 所说的限制)。我的实现使用 RPC 使用 Texture2D.EncodeToPNG 发送一个字节数组,然后在客户端收到它后对其进行解码。

要将字节数组转换回图像,可以使用Texture2D.LoadImage 方法。

发送其他多媒体类型的方法类似,只是编码/解码方法不同。

【讨论】:

【参考方案3】:

PhotonStream 允许您通过网络传输任何 byte[] 数据。 理论上,任何数据类型都可以转换成byte[],并在接收端解码。


下面的示例脚本只是一个设置最少的示例。 参考自:https://frozenmist.com/docs/apis/fmetp-stream/pun2-example/

还可以使用流行的第三方插件(如 FMETP STREAM)实时流式传输视频、音频和远程命令,该插件具有本机快速编码器,可实时捕获您的游戏视图和桌面视图,甚至与移动和 VR 设备兼容。

using Photon.Pun;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

// ref: https://frozenmist.com/docs/apis/fmetp-stream/pun2-example/
public class FMStreamPUN : Photon.Pun.MonoBehaviourPun, IPunObservable 
    private Queue<byte[]> appendQueueSendData = new Queue<byte[]>();
    public int appendQueueSendDataCount  get  return appendQueueSendData.Count;  

    public UnityEventByteArray OnDataByteReadyEvent = new UnityEventByteArray();

    public void OnPhotonSerializeView(PhotonStream stream, PhotonMessageInfo info) 
        if (stream.IsWriting) 
            //Send the meta data of the byte[] queue length
            stream.SendNext(appendQueueSendDataCount);
            //Sending the queued byte[]
            while(appendQueueSendDataCount > 0) 
                byte[] sentData = appendQueueSendData.Dequeue();
                stream.SendNext(sentData);
            
        

        if (stream.IsReading) 
            if (!photonView.IsMine) 
                //Get the queue length
                int streamCount = (int)stream.ReceiveNext();
                for (int i = 0; i < streamCount; i++) 
                    //reading stream one by one
                    byte[] receivedData = (byte[])stream.ReceiveNext();
                    OnDataByteReadyEvent.Invoke(receivedData);
                
            
        
    

    public void Action_SendData(byte[] inputData) 
        //inputData(byte[]) is the encoded byte[] from your encoder
        //doesn't require any stream, when there is only one player in the room
        if(PhotonNetwork.CurrentRoom.PlayerCount > 1) appendQueueSendData.Enqueue(inputData);
    

【讨论】:

嗨@sharimken,你成功实现了 Frozen Mist 编写的代码吗?我也使用他们的资产并尝试使用上面给出的代码使用 PUN 2 实现流式传输,但性能并不成功。游戏变得如此滞后,具有解码器本身的接收器将在流媒体给出的实际更新后最多 5-7 秒更新动作。 我对上述代码的实现: 1. 创建包含 FMStreamPun.cs 和 Photon 视图的网络对象的预制件 2. 自加载游戏场景以来,当将流式传输其游戏的玩家进入房间时,该对象被实例化. 3. 当带有解码器的客户端进入房间时,流发生,并且在 Start() 上将找到具有 FMStreamPUN 的可用网络对象,并将通过 FMStreamPUN 的 OnDataByteReadyEvent 处理图像数据。 4. 是的,Action_SendData 由流媒体客户端的编码器调用。由于 FMStreamPUN 对象将被相应地实例化。谢谢 我们也可以在我们这边重现这个问题,感谢您指出 PUN2 性能问题。我们发现一个临时解决方案是手动控制流量。例如,如果在一秒钟内发送的字节数超过 32k,我们不应该流式传输帧,直到流量低于此数字。 我 99% 确定 PUN2 的 UDP 是可靠的,即使我选择了不可靠的发送方式,它也会尝试重新发送丢失的数据。因此,当您拥有大量数据时,累积的延迟可能会很大。

以上是关于有没有办法使用 Photon Pun2 或 Photon Chat 发送或接收图像、音频和视频?的主要内容,如果未能解决你的问题,请参考以下文章

基于PUN2的VR多人在线交互解决方案

Unity联网插件(PUN)

PUN2:通过 RPC 调用指定一个实例化的玩家游戏对象

使用 Unity 和 Photon PUN,有没有办法在运行时使用 SetTile() 同步更改对瓷砖地图的更改?

PUN 2.0 相机为每个玩家渲染

Unity/Pun2:2个玩家互相控制