Version: 2021.3
言語: 日本語
UploadHandler の作成
オーディオ

DownloadHandler の作成

重要: UNet は非推奨のソリューションになり、現在、新しい Multiplayer とネットワーキングソリューション (Netcode for GameObjects) が開発中です。詳細は、GameObjects Web サイトの Unity Netcode を参照してください。

DownloadHandlersにはさまざまなタイプがあります。

  • DownloadHandlerBuffer は簡易なデータストレージとして使用されます。
  • DownloadHandlerFile は少ないメモリフットプリントでファイルをダウンロードし、ディスクに保存するために使用されます。
  • DownloadHandlerTexture は画像をダウンロードするために使用されます。
  • DownloadHandlerAssetBundle はアセットバンドルをフェッチするために使用されます。
  • DownloadHandlerTexture はオーディオ ファイルをダウンロードするために使用されます。
  • DownloadHandlerMovieTexture はビデオファイルのダウンロードに使用されます。 MovieTexture (ムービーテクスチャ) は非推奨であるため、ビデオのダウンロードとムービーの再生には VideoPlayer を使用することをお勧めします。
  • DownloadHandlerScript は特殊クラスです。それ自体では何も行いません。ただし、このクラスはユーザー定義のクラスによって継承が可能です。 このクラスは UnityWebRequest システムからコールバックを受け取り、ネットワークからデータを取得したときに完全にカスタム処理するために使用します。

API は DownloadHandlerTexture のインターフェースに似ています。

UnityWebRequest には disposeDownloadHandlerOnDispose というプロパティがあります。このデフォルトは true です。このプロパティが true の場合、UnityWebRequest オブジェクトが破棄されると、添付されたダウンロードハンドラーで Dispose() も呼び出され、レンダリングを無効にします。ダウンロードハンドラーへの参照を UnityWebRequest への参照より長く保持している場合は、disposeDownloadHandlerOnDispose を false に設定する必要があります。

DownloadHandlerBuffer

このダウンロードハンドラーは最も簡単で、たいていのケースを処理できます。このハンドラーは受け取ったデータをネイティブコードバッファーに格納します。ダウンロードが終了すると、バイト配列またはテキスト文字列で、バッファーされたデータにアクセスできます。

using UnityEngine;
using UnityEngine.Networking;
using System.Collections;


public class MyBehaviour : MonoBehaviour {
    void Start() {
        StartCoroutine(GetText());
    }

    IEnumerator GetText() {
        UnityWebRequest www = new UnityWebRequest("https://www.my-server.com");
        www.downloadHandler = new DownloadHandlerBuffer();
        yield return www.SendWebRequest();

        if (www.result != UnityWebRequest.Result.Success) {
            Debug.Log(www.error);
        }
        else {
            // 結果をテキストで表示
            Debug.Log(www.downloadHandler.text);

            // または、結果をバイナリデータで取得
            byte[] results = www.downloadHandler.data;
        }
    }
}

DownloadHandlerFile

これは大きなファイル用の特別なダウンロードハンドラです。ダウンロードされたバイトを直接ファイルに書き込むので、ダウンロードするファイルのサイズに関係なくメモリの使用量は少なくなります。他のダウンロードハンドラとの違いは、このデータは取り出すことができず、すべてのデータはファイルに保存されます。

using System.Collections;
using System.IO;
using UnityEngine;
using UnityEngine.Networking;

public class FileDownloader : MonoBehaviour {

    void Start () {
        StartCoroutine(DownloadFile());
    }

    IEnumerator DownloadFile() {
        var uwr = new UnityWebRequest("https://unity3d.com/", UnityWebRequest.kHttpVerbGET);
        string path = Path.Combine(Application.persistentDataPath, "unity3d.html");
        uwr.downloadHandler = new DownloadHandlerFile(path);
        yield return uwr.SendWebRequest();
        if (uwr.result != UnityWebRequest.Result.Success)
            Debug.LogError(uwr.error);
        else
            Debug.Log("File successfully downloaded and saved to " + path);
    }
}

DownloadHandlerTexture

DownloadHandlerBuffer を使用して画像ファイルをダウンロードし、それから Texture.LoadImage を使用して生のバイトからテクスチャを作成する代わりに、DownloadHandlerTexture を使用する方が効率的です。

このダウンロードハンドラーは、受信したデータを UnityEngine.Texture に格納します。ダウンロードが完了すると、JPEG と PNG を有効な UnityEngine.Texture オブジェクトにデコードします。各 DownloadHandlerTexture オブジェクトごとに 1 つのUnityEngine.Texture だけしか作成されません。ですから、ガベージコレクションによるパフォーマンスの低下を軽減します。ハンドラーは、バッファリング、解凍、テクスチャの作成をネイティブコードで実行します。さらに、解凍とテクスチャの作成を、メインスレッドでなくワーカースレッドで実行するため、大きなテクスチャを読み込むときにフレーム時間を向上させます。

最後に、DownloadHandlerTexture は、最終的にテクスチャ自体を作成するときにのみマネージドのメモリを割り当てます。このため、スクリプトでバイトからテクスチャへの変換を実行する際のガベージコレクションのオーバーヘッドを排除します。

以下の例では、PNG ファイルをインターネットからダウンロードし、スプライトに変換し、画像 に割り当てます。

using UnityEngine;
using UnityEngine.UI;
using UnityEngine.Networking;
using System.Collections;

[RequireComponent(typeof(Image))]
public class ImageDownloader : MonoBehaviour {
    Image _img;

    void Start () {
        _img = GetComponent<UnityEngine.UI.Image>();
        Download("https://www.mysite.com/myimage.png");
    }

    public void Download(string url) {
        StartCoroutine(LoadFromWeb(url));
    }

    IEnumerator LoadFromWeb(string url)
    {
        UnityWebRequest wr = new UnityWebRequest(url);
        DownloadHandlerTexture texDl = new DownloadHandlerTexture(true);
        wr.downloadHandler = texDl;
        yield return wr.SendWebRequest();
        if (wr.result == UnityWebRequest.Result.Success) {
            Texture2D t = texDl.texture;
            Sprite s = Sprite.Create(t, new Rect(0, 0, t.width, t.height),
                Vector2.zero, 1f);
            _img.sprite = s;
        }
    }
}

DownloadHandlerAssetBundle

この特化したダウンロードハンドラーの利点は、Unity のアセットバンドルシステムにデータをストリーミングできることです。アセットバンドルシステムが十分なデータを受け取ると、アセットバンドルはUnityEngine.AssetBundle オブジェクトとして利用できます。UnityEngine.AssetBundle オブジェクトのコピーは 1 つだけ作成されます。これにより、ランタイムメモリの割り当てと、アセットバンドルの読み込みによるメモリへの影響が大幅に軽減されます。また、完全にダウンロードされていないときにアセットバンドルを部分的に使用することができます。ですから、アセットをストリーミングすることができます。

すべてのダウンロードと解凍はワーカースレッドで行われます。

アセットバンドルは、DownloadHandlerAssetBundle オブジェクトをとおしてダウンロードされます。このオブジェクトには、アセットバンドルを取得する特別な assetBundle プロパティがあります。

アセットバンドルシステムの仕組みにより、すべてのアセットバンドルには関連付けられたアドレスが必要です。一般的には、これはアセットバンドルが位置する名目上の URL (リダイレクト前のURL ) です。ほとんどの場合、UnityWebRequest に渡したのと同じ URL を渡す必要があります。高レベル API (HLAPI) を使用する場合、これは本人の判断で行ってください。

using UnityEngine;
using UnityEngine.Networking;
using System.Collections;

public class MyBehaviour : MonoBehaviour {
    void Start() {
        StartCoroutine(GetAssetBundle());
    }

    IEnumerator GetAssetBundle() {
        UnityWebRequest www = new UnityWebRequest("https://www.my-server.com");
        DownloadHandlerAssetBundle handler = new DownloadHandlerAssetBundle(www.url, uint.MaxValue);
        www.downloadHandler = handler;
        yield return www.SendWebRequest();

        if (www.result != UnityWebRequest.Result.Success) {
            Debug.Log(www.error);
        }
        else {
            // AssetBundle を取得
            AssetBundle bundle = handler.assetBundle;
        }
    }
}

DownloadHandlerAudioClip

このダウンロードハンドラーは、オーディオファイルをダウンロードするために最適化されています。 DownloadHandlerBuffer を使用して生のバイトをダウンロードしてから AudioClip を作成する代わりに、このダウンロードハンドラーを使用してより便利に処理できます。

using System.Collections;
using UnityEngine;
using UnityEngine.Networking;

public class AudioDownloader : MonoBehaviour {

    void Start () {
        StartCoroutine(GetAudioClip());
    }

    IEnumerator GetAudioClip() {
        using (var uwr = UnityWebRequestMultimedia.GetAudioClip("https://myserver.com/mysound.ogg", AudioType.OGGVORBIS)) {
            yield return uwr.SendWebRequest();
            if (uwr.result != UnityWebRequest.Result.Success) {
                Debug.LogError(uwr.error);
                yield break;
            }

            AudioClip clip = DownloadHandlerAudioClip.GetContent(uwr);
            // オーディオクリップを使用
        }
    }
}

DownloadHandlerScript

ダウンロードしたデータの処理を完全に制御する必要があるユーザのために、Unity はDownloadHandlerScript クラスを提供します。

デフォルトでは、このクラスのインスタンスは何も行いません。ただし、DownloadHandlerScript から独自のクラスを派生させる場合、特定の関数をオーバーライドして、ネットワークからデータが到着するときコールバックを受け取るためにその関数を使用します。

注意 実際のダウンロードはワーカースレッド上で行われますが、すべての DownloadHandlerScript コールバックはメインスレッド上で動作します。 これらのコールバック中に負荷の高い計算操作を行なわないでください。

オーバーライドする関数

ReceiveContentLength()

protected void ReceiveContentLength(long contentLength);

この関数は、Content Length ヘッダーが受信されたときに呼び出されます。UnityWebRequest の処理中にサーバーが 1つ以上のリダイレクト応答を送信すると、このコールバックは複数回発生することがあります。

OnContentComplete()

protected void OnContentComplete();

この関数は UnityWebRequest がサーバーからすべてのデータを完全にダウンロードし、それを ReceiveData コールバックに転送したときに呼び出されます。

ReceiveData()

protected bool ReceiveData(byte[] data, long dataLength);

この関数は、リモートサーバーからデータを受領した後に、フレームごとに 1 回呼び出されます。 data 引数には、リモートサーバーから受信した生のバイトが含まれます。また、 dataLength はデータ配列内の新しいデータの長さを示します。

事前に割り当てられたデータバッファを使用しない場合、システムはこのコールバックを呼び出すたびに新しいバイト配列を作成し、dataLength は常に data.Length と等しくなります。 事前に割り当てられたデータバッファを使用する場合は、データバッファが再利用され、更新されたバイト数を見つけるために dataLength を使用する必要があります。

この関数には、true または false のいずれかの戻り値が必要です。false を返すと、システムは直ちに UnityWebRequest を中止します。true を返すと、処理は正常に続行されます。

ガーベージコレクションオーバーヘッドの回避

もっと上級レベルの Unity ユーザーの多くは、ガベージコレクションのために CPU スパイクを減らすことを気にかけています。これらのユーザのために、UnityWebRequest システムは、ダウンロードされたデータを DownloadHandlerScript のReceiveData コールバックに配信するために使用されるマネージドのコードのバイト配列の事前割り当てを許可します。

この関数を使用すると、DownloadHandlerScript 派生クラスを使用してダウンロードしたデータを取得するときに、マネージドのコードのメモリ割り当てを完全に排除します。

DownloadHandlerScript をあらかじめ割り当てられたマネージバッファで動作させるには、バイト配列を DownloadHandlerScript のコンストラクタに渡します。

注意 バイト配列のサイズは、各フレームで ReceiveData コールバックに渡されるデータ量を制限します。データがゆっくりと、多くのフレームにわたって到着した場合、バイト配列が小さすぎる可能性があります。

using UnityEngine;
using UnityEngine.Networking;

public class LoggingDownloadHandler : DownloadHandlerScript {

    // 標準のスクリプトされたダウンロードハンドラー。各 ReceiveData コールバックにメモリを割り当てます。

    public LoggingDownloadHandler(): base() {
    }

    // 事前に割り当てられたスクリプトされたダウンロードハンドラーは、
    //提供されたバイト配列を再利用してデータを配信します。 
    //メモリ割り当てを排除します。


    public LoggingDownloadHandler(byte[] buffer): base(buffer) {
    }

    //  DownloadHandler 基本クラスに必須。  'bytes' プロパティを示すときに呼び出されます。

    protected override byte[] GetData() { return null; }

    // ネットワークからデータを受信すると、フレームごとに 1 回呼び出されます。

    protected override bool ReceiveData(byte[] data, int dataLength) {
        if(data == null || data.Length < 1) {
            Debug.Log("LoggingDownloadHandler :: ReceiveData - received a null/empty buffer");
            return false;
        }

        Debug.Log(string.Format("LoggingDownloadHandler :: ReceiveData - received {0} bytes", dataLength));
        return true;
    }

    // すべてのデータがサーバーから受信され、ReceiveData を介して配信されるときに呼び出されます。

    protected override void CompleteContent() {
        Debug.Log("LoggingDownloadHandler :: CompleteContent - DOWNLOAD COMPLETE!");
    }

    // Content-Length ヘッダーをサーバーから受信したときに呼び出されます。

    protected override void ReceiveContentLengthHeader(ulong contentLength) {
        Debug.Log(string.Format("LoggingDownloadHandler :: ReceiveContentLength - length {0}", contentLength));
    }
}
UploadHandler の作成
オーディオ