エンジン統合

統合

Genvid MILE SDK API は、C: genvid.h で記述される単一のヘッダファイルで構成されます。SDK を統合するには、ヘッダファイルをインクルードし、適切な共有ライブラリを追加する必要があります。

  1. コンパイル環境のインクルードパスに genvid.h を追加します。
  2. 共有ライブラリの適切なバージョンにリンクします。
    Genvid MILE SDK には、Windows 用 32 ビット、64 ビットの両バージョンが|含まれています。
  3. ゲームと一緒に、対応する DLL をデプロイします。
    通常は、ゲームの実行ファイルと一緒に、Genvid.dll をコピーします。
  4. 処理がうまくいくことを確認します。
    すべての Genvid MILE SDK メソッドは GenvidStatus を返し、操作が正しく行われたかどうかを判断するために使用できます。const char* Genvid_StatusToString(const GenvidStatus status) を用いて enum 値を const char* 値に変換することも可能です。

プログラムフロー

Genvid MILE SDK のプログラムフローは、次の 4 つのステップで構成されます。

  1. 初期化
  2. 設定
  3. ライブ配信
  4. 終了
Genvid program flow

図 100 Genvid のプログラムフロー

初期化

他のルーチンを呼び出す前に、 GenvidStatus Genvid_Initialize() を呼び出して、Genvid ライブラリを初期化します。

GenvidStatus gs = Genvid_Initialize();
if(gs != GenvidStatus_Success)
{
   // Something bad happened; you can't use Genvid.
   return false;
}

初期化は非同期ハンドラを作成し、Consul に接続して設定を読み込みます。接続がうまくいかなかった場合、自動的に再試行を行います。

Genvid ライブラリを適切に初期化しないで Genvid MILE SDK ルーチンを呼び出すと、 GenvidStatus_UninitializedSDK エラーが発生します。

設定を読み込むと、リクエストの処理を開始します。

設定

ライブラリの初期化後、streamID に一意の名前を使用してストリームを作成します。

重要

ストリーム名の一部に、 genvid を使用することはできません。

「ストリーム」 とは、Genvid がオーディオ、ビデオ、ゲームデータに関連付けるために使用する言葉です。streamID は、コールする場所から、特定ストリームを参照するために使用します。

GenvidStatus Genvid_CreateStream(const char *streamID) を呼び出して、ストリームを作成します。

GenvidStatus gs;
gs = Genvid_CreateStream("audio");
if(gs != GenvidStatus_Success)
{
   return false;
}
gs = Genvid_CreateStream("video");
if(gs != GenvidStatus_Success)
{
   return false;
}
gs = Genvid_CreateStream("game.players");
if(gs != GenvidStatus_Success)
{
   return false;
}
gs = Genvid_CreateStream("game.camera");
if(gs != GenvidStatus_Success)
{
   return false;
}

データをストリームに送信する前に、設定が必要なパラメータがいくつか存在します。

パラメータの設定には、次のような関数を使用します。

Genvid_SetParameter() 関数は、整数、浮動小数点数、ポインタ値のバリエーションです。各関数には、次の入力が必要です。

  • streamID
    初期化中に設定するストリーム名。
  • parameter key
    変更するパラメータ名。キーは大文字、小文字を区別しません。
  • parameter value
    使用する変数の特定の型です。

適切なパラメータキーを設定しないで Genvid_SetParameter() 関数を呼び出すと、 GenvidStatus_InvalidParameter エラーが発生します。

共通パラメータ

framerate パラメータは、期待される video-data のフレームレートを Genvid に伝えます。整数、または浮動小数点数を使用できます。

GenvidStatus gs;
// Sending video 30 times a second.
gs = Genvid_SetParameterInt("video", "framerate", 30);
if(gs != GenvidStatus_Success)
{
   return false;
}
// Sending slow data once every 10 seconds.
gs = Genvid_SetParameterFloat("slowdata", "framerate", 0.1f);
if(gs != GenvidStatus_Success)
{
   return false;
}

framerate を定義した場合、タイムコードは近似値に丸められます。新規ストリームのデフォルトの framerate は 30 Hz です。

video source パラメータは、ライブ配信時に、ビデオデータの取得先を指定します。Genvid MILE SDK は現時点で、D3D11 ソースだけをサポートしているため、DXGI swap chain または 2D texture となります。

IDXGISwapChain を指定するには、ポインタで Video.Source.IDXGISwapChain パラメータキーを使用します。

IDXGISwapChain* mySwapChain = nullptr;
// Some code assigning mySwapChain to a valid value...
GenvidStatus gs = Genvid_SetParameterPointer("video", "Video.Source.IDXGISwapChain", mySwapChain);
if(gs != GenvidStatus_Success)
{
   return false;
}

2D テクスチャリソースハンドルの場合、 Video.Source.ID3D11Texture2D を使用します。

ID3D11Texture2D* myTexture = nullptr;
// Some code assigning myTexture to a valid value...
GenvidStatus gs = Genvid_SetParameterPointer("video", "Video.Source.ID3D11Texture2D", myTexture);
if(gs != GenvidStatus_Success)
{
   return false;
}

ビデオソースパラメータを指定すると、自動フレームグラブが有効になります。レンダリングスレッドからフレームが準備できたら、Genvid に伝える必要があります (ライブ動画配信 を参照)。

カスタムキャプチャメソッドを使用している場合、Genvid は、さまざまなピクセルフォーマットの raw バッファを渡すことができます。それらの形式を使用する場合、ビデオソースを指定する代わりに、バッファの幅、高さ、ピクセルフォーマットを指定します。

assert(description.Format == DXGI_FORMAT_R8G8B8A8_UNORM);
gs = Genvid_SetParameterInt(sStream_Video.c_str(), "video.pixel_format", GenvidPixelFormat_R8G8B8A8);
assert(gs == GenvidStatus_Success);
gs = Genvid_SetParameterInt(sStream_Video.c_str(), "video.width", description.Width);
assert(gs == GenvidStatus_Success);
gs = Genvid_SetParameterInt(sStream_Video.c_str(), "video.height", description.Height);
assert(gs == GenvidStatus_Success);

重要

このオプションを使用する時にビデオソースを設定することで、自動キャプチャが有効になり、競合が発生します。

使用するフォーマットをパックする必要があります。つまり、フレームバッファのピッチが映像の幅と同じである必要があります。

Genvid MILE SDK は、オーディオストリームを自動キャプチャします。自動キャプチャを有効にするには、Audio.Source.WASAPI のパラメータに 1 を設定します。

GenvidStatus gs = Genvid_SetParameterInt("audio", "Audio.Source.WASAPI", 1);
if(gs != GenvidStatus_Success)
{
   return false;
}

注釈: WASAPI 自動キャプチャーを有効にすると、オーディオストリームの粒度がサンプリングレートに設定されます。

GENVID_AUDIO_DEVICE 環境変数は、使用するオーディオデバイスを定義する文字列を保持します。ローカルモードでは、デフォルトでは定義されませんが、クラウド構成では 「CABLE Input」 に定義されるため、通常はこれが使用されます。指定したデバイスが見つからない場合、デフォルトのオーディオエンドポイントが使用されます。

オーディオのフレームレートは、ビデオソースの設定値と同じ値に設定することを推奨します。

オーディオ自動キャプチャが有効になっている場合、デフォルトのミキシングフォーマットとサンプリングレートが使用されます。デフォルトでは、Windows は、48 kHz のステレオ浮動小数点数サンプルを使用します。

自動キャプチャ (現在、Unity engine でサポート) を使用しないでキャプチャすることもできます。データ送信前に、オーディオストリームに 3 つのパラメータを設定する必要があります。

  1. audio.rate
  2. audio.format
  3. audio.channels

粒度は、タイムコードをスナップする精度を定義します。どのストリームにも設定可能です。データをサンプリングしたタイムコードをより正確に表現するために、サンプルレートに設定することをお勧めします。

GenvidStatus gs;
float sampleRate = 48000;
gs = Genvid_SetParameterFloat("audio", "granularity", sampleRate);
if (gs != GenvidStatus_Success)
{
   return false;
}

指定しない場合、粒度のデフォルトはサンプルレートになります。サンプルレートが利用できない場合、粒度はデフォルトでフレームレートになります。

以下の表は、主要なストリームパラメータです。

注釈

パラメータキーは大文字、小文字を区別しません。

表 17 主要なストリームパラメータ。
キー サポートするメソッド 説明 デフォルト
framerate フロート set と get フレームレートを指定します。 30
granularity フロート set と get 粒度は、タイムコードをスナップする精度を定義します。利用可能な場合は、デフォルトはサンプルレートになります。利用できない場合、フレームレートになります。 1.0
video.source.idxgiswapchain ポインタ set と get ビデオソースで使用する D3D11 スワップチェーンを指定します。これにより、ビデオ自動キャプチャが有効になります。このキャプチャ方法を使用すると、id3d11texture2d キャプチャは使用できません。 N/A
video.source.id3d11texture2d ポインタ set と get ビデオソースで使用する D3D11 テクスチャを指定します。これにより、ビデオ自動キャプチャが有効になります。このキャプチャ方法を使用すると、idxgiswapchain キャプチャは使用できません。 N/A
video.pixel_format 整数 set ビデオフレームのピクセルフォーマットを設定します。フォーマットは GenvidPixelFormat で指定します。このオプションには、ビデオ自動キャプチャとの互換性はありません。 N/A
video.width 整数 set ビデオフレームの幅を設定します。このオプションには、ビデオ自動キャプチャとの互換性はありません。 N/A
video.height 整数 set ビデオフレームの高さを設定します。このオプションには、ビデオ自動キャプチャとの互換性はありません。 N/A
video.useopenglconvention 整数 set このパラメータを1に設定すると、ビデオストリームが水平軸に沿って反転します。 0
audio.source.wasapi 整数 set と get WASAPI オーディオキャプチャのオン、オフ (1、0) を切り替えます。これにより、オーディオ自動キャプチャが有効になります。 0
audio.rate 整数 set と get オーディオのサンプリングレートを変更します。 0
audio.format 整数 set と get オーディオフォーマットを GenvidAudioFormat_S16LE または GenvidAudioFormat_F32LE に変更します。 N/A
audio.channels 整数 set と get オーディオのチャンネル数を変更します。 0

パラメータ取得

以下の関数を使用して、Genvid MILE SDK の現在のステータスを取得できます。

『Genvid_GetParameter』 関数は、整数、浮動小数点数、ポインタ値の、同じルーチンのバリエーションです。

Consul からパラメータキーの値を取得するには、以下を使用します。

Genvid_GetParameterInt() および、 Genvid_GetParameterFloat() には以下を使用します。

  • ストリーム ID に genvid.kv
  • キー名に paramKey
  • 値の格納先に paramValue
int score = 0;
GenvidStatus gs = Genvid_GetParameterInt("genvid.kv", "genvid/game/score", &score);

float time = 0.0f;
GenvidStatus gs = Genvid_GetParameterFloat("genvid.kv", "genvid/game/time", &time);

Genvid_GetParameterUTF8() には以下を使用できます。

  • ストリーム ID に任意の文字列
  • キー名に paramKey
  • 値を受け取るコンテナに dstBuffer
  • バッファサイズに dstBufferSize

受信した key が利用可能なアロケーションサイズより小さい場合、 GenvidStatus_Incomplete の警告が返されます。

char playerName[10];
GenvidStatus gs = Genvid_GetParameterUTF8("genvid.kv", "genvid/game/playername", playerName, 10);

サブスクリプション

ここまでで、視聴者にさまざまな情報を提供する方法を紹介してきました。ここからは、ゲームが Genvid のスタックから何を受け取れるのかを見てみましょう。

ゲームがサブスクライブできる受信メッセージには 2 種類あります。イベントとコマンドです。

イベント

視聴者は、 web API を通じて、 イベント をゲームに返します。イベントは、潜在的に大規模な視聴者のフィードバックから処理されたゲームの情報を与える key-value オブジェクトで構成されています。

注釈

また、 Webgateway サービスを使用して、認証されたマシンからイベントのバッチを送信することもできます。視聴者のブラウザから直接イベントを送信したくない場合に便利です。

ゲーム側の SDK では、コールバックを subscription function に渡すことで、処理したイベント (例: Genvid サービスで処理を行った後のイベント) にアクセスできます。

具体的には、イベントを購読するには GenvidStatus Genvid_Subscribe(const char *id, GenvidEventSummaryCallback callback, void *userData) を使用します。特定の興味のあるイベント、コールバック、コールバックに送信するオプションのデータポインタを指定する必要があります (必要ない場合は nullptr を使用します)。

GenvidStatus gs = Genvid_Subscribe("some_event_id", &SomeEventCallback, nullptr);

このイベントコールバックには以下のシグネチャがあります。

void SomeEventCallback(const GenvidEventSummary* summary, void* userData*)
{
    // summary->id would be equal to "some_event_id".
    // summary->results[] would contain the results of the MapReduce.
    // userData would contain nullptr (but could be anything the user specifies).
    // ...
}

コールバックについては typedef void (*GenvidEventSummaryCallback) (const GenvidEventSummary *summary, void *userData) を参照してください。

返される構造については struct GenvidEventSummary を参照してください。

MapReduce 処理の定義については、 イベントの概要 を参照してください。

異なるイベント ID を使用したり、データポインタを使用して、同じコールバックを登録できます。

コマンド

コマンド は、ゲームのプロセスに簡潔な指示を送信するために使用する特別な即時メッセージです。コマンドは非スケーラブルであるため、使用する際には注意が必要です。

使用例としては、次に読み込むマップをマッチ管理の Web ページから直接制御することができます。

Webgateway サービスで、 POST /commands/game URI を使用してコマンドを送信します。

警告

コマンドを、視聴者の Web サイトから送信すべきではありません。配信ストリームは何千人もの視聴者をホストできることを覚えておいてください。視聴者のフィードバックを収集し、それに応じてゲームループを変更するために、提供されている イベントシステム を使用することを検討してください。視聴者の入力ごとに多くのコマンドをゲームに送信すると、配信に悪影響を与えたり、ゲームがクラッシュしたりすることがあります。

コマンドサブスクリプションは GenvidStatus Genvid_SubscribeCommand(const char *id, GenvidCommandCallback callback, void *userData) を使用します。

GenvidStatus gs = Genvid_SubscribeCommand("some_command_id", &SomeCommandCallback, nullptr);

コマンドコールバックには、以下のシグネチャがあります。

void SomeCommandCallback(const GenvidCommandResult* result, void* userData)
{
    // result->id would be equal to "some_event_id".
    // result->value would contain whatever string was sent.
    // userData would contain nullptr (but could be anything the user specifies).
    // ...
}

コールバックについては typedef void (*GenvidCommandCallback) (const GenvidCommandResult *result, void *userData) を参照してください。

返される構造については struct GenvidCommandResult を参照してください。

webgateway サービスが提供する /command エンドポイントについては、Webgateway サービス API を参照してください。

ライブ配信

ライブ配信するデータが発生するたびに、Genvid に指示を送る必要があります。

また、タイムコードをすべてのデータチャンクに関連付けする必要があり、Genvid がストリーム内に適切に配置することができます。順序が前後するタイムコード (たとえば、直前のタイムコードより前のタイムコードなど) を指定すると、未定義のエラーが発生します。

タイムコード

Genvid MILE SDK は、現在のタイムコードを取得するためのルーチン GenvidTimecode Genvid_GetCurrentTimecode() を提供し、特別な typedef int64_t GenvidTimecode の値を返します。

-1 のタイムコードを使用するのは、 Genvid_GetCurrentTimecode() をコールして、その結果を使用するのと同じことです。

複数のデータチャンクで同じタイムコードを共通で使用するには、一度 Genvid_GetCurrentTimecode() を呼び出して、その後の Genvid_Submit*Data() 呼び出しの結果を再利用します。

GenvidTimecode Genvid_GetPreviousTimecode() を呼び出して、 Genvid_GetCurrentTimecode() の直前の戻り値を取得できます。これは、複数のコードの場所で同じタイムコードを使用する場合に使用できますが、 GenvidTimecode を使用するのは問題があります。

オーディオのライブ配信

Genvid は現在、自動キャプチャマニュアルキャプチャ の 2 つのオーディオモードをサポートしています。

自動キャプチャ は、オーディオ出力デバイスのサウンドを自動的にキャプチャし、内部で Genvid_SubmitAudioData() を呼び出して送信します。

マニュアルキャプチャ は、ゲーム側の関数 Genvid_SubmitAudioData() を明示的に呼び出す必要があります。

自動キャプチャ はアクティブにするだけで動作する、最も簡単な方法です。

オーディオデータのストリーミングの使用や設定方法については、 共通パラメータ を参照してください。

表 18 自動キャプチャ。
長所 短所
オーディオキャプチャシステムは、SDK に実装済み すべてのオーディオデータ (スピーカー、入力、マイクなど) をキャプチャ
自動オーディオ設定 (フォーマット、レート、チャンネル)  
ゲームエンジンに左右されない  
表 19 マニュアルキャプチャ。
長所 短所
ゲームエンジンに左右されない ゲーム側でのオーディオキャプチャの実行が必要
オーディオデータストリームの制御  
ローカルモードでのサウンドの問題を回避  

ライブ動画配信

レンダリングされたフレームが準備できたら、 GenvidStatus Genvid_SubmitVideoData(const GenvidTimecode timecode, const char *streamID, const void *videoData, const int videoDataSize を呼び出して、フレームのキャプチャとエンコードが可能なことを、Genvid に伝えます。

ビデオソースの設定はすでに完了しているため、タイムコードと streamID を送信するだけで OK です。

詳細は、 Video Source Parameter を参照してください。

上記の理由により、この例では、最後の 2 つのパラメータには、null ポインタと 0 を送信しています。

GenvidTimecode tc = Genvid_GetCurrentTimecode();
GenvidStatus gs = Genvid_SubmitVideoData(tc, "video", nullptr, 0);
if(gs != GenvidStatus_Success)
{
   return false;
}

このルーチンが呼び出されると、Genvid MILE SDK がビデオソースをキャプチャ、エンコードして、ストリーミングを行います。できるだけ効率よく行うため、この処理は非同期で実行されます。

ゲームデータのライブ配信

ゲームデータのすべてのチャンクが、実際のゲームデータを含む、バイト配列 (データとサイズ)、タイムコードと streamID を指定する必要があります。

注釈

Genvid は現在、データの仮定を行わず、サービスを使用して raw バイトを送信します。帯域幅の節約のため、ゲームデータフォーマットのより厳しい要件を検討中です。

次の例では、 GenvidStatus Genvid_SubmitGameData (const GenvidTimecode timecode, const char *streamID, const void *gameData, const int gameDataSize) で、別のストリームで同じタイムコードを使用して、カメラとプレイヤーデータをストリーミングする方法を示しています。

// Fake runtime data.
std::string playerData = R"({ "P1": {"position": [0, 0, 0]}, "P2": {"position":�[1, 0, 0]} })";
std::string cameraData = R"({ "matrix": [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1]�})";

GenvidStatus gs;
GenvidTimecode tc = Genvid_GetCurrentTimecode();
gs = Genvid_SubmitGameData(tc, "game.player", playerData.data(), (int)playerData.size());
if(gs != GenvidStatus_Success)
{
    return false;
}
gs = Genvid_SubmitGameData(tc, "game.camera", cameraData.data(), (int)cameraData.size());
if(gs != GenvidStatus_Success)
{
    return false;
}

ゲームアノテーションのライブ配信

アノテーションは、データのライブ配信と同様です。大きな違いは、システムと JavaScript による情報の取り扱い方法です。アノテーションはストリーム固有のもので、1 ストリーム、1 フレームあたり 256 アノテーションに制限されています。

次のサンプルでは、 GenvidStatus Genvid_SubmitAnnotation (const GenvidTimecode timecode, const char *streamID, const void *annotationData, const int annotationDataSize) でのキル確認のアノテーション送信方法を紹介しています。

// Fake runtime data.
std::string confirmKills = R"({ "kills": ["Player1", "Player2"] })";

GenvidStatus gs;
GenvidTimecode tc = Genvid_GetCurrentTimecode();
gs = Genvid_SubmitAnnotation(tc, "game.confirmKills", playerData.data(), (int)playerData.size());
if(gs != GenvidStatus_Success)
{
    return false;
}

ゲーム通知

通知は、リアルタイム更新のように、情報をできるだけはやく Web サイトに送信します。通知は、永続的なものではなく、タイムコードとの関連付けも行いません。

次のサンプルは、 GenvidStatus Genvid_SubmitNotification (const char* notificationID, const void* notificationData, const int notificationDataSize) でのプレイヤーの popularity に関する通知の送信方法を紹介しています。

// Fake runtime data.
std::string popularityData = R"({ "players": [{"name":"player1", "popularity": 2},{"name":"player2", "popularity": 10}] })";

GenvidStatus gs;
gs = Genvid_SubmitNotification("game.popularity", popularityData.data(), (int)popularityData.size());
if(gs != GenvidStatus_Success)
{
    return false;
}

ゲームが新たにストリームを作成する前に、 Genvid クラスタ を終了させる必要があります。その後、新しいストリームの作成と設定を行ってクラスタを開始します。この制約は、クラスタが潜在的なストリームを適切に処理するために、リソースを予約できるようにするために存在しています。

コールバックの検証

ライブ配信中にイベントのコールバックや、コマンドがある場合、ライブ配信中のコマンドは、結果が出てから GenvidStatus Genvid_CheckForEvents() でコールバックを使用してください。

できるだけ早く結果を得るために、このチェックを定期的に行うことを推奨します。チュートリアルのサンプルでは、データの送信時に毎回 Genvid_CheckForEvents() を使用しています。

注釈

イベントが存在する場合、 GenvidStatusGenvidStatus_Success を返します。イベントが存在しない場合は、 GenvidStatus_ConnectionTimeout が戻ります。

終了

ストリームの処理が完了したら、 GenvidStatus Genvid_DestroyStream(const char *streamID) と適切な streamID で、ストリームの割り当てを解除できます。

Genvid_DestroyStream("game.player");
Genvid_DestroyStream("came.camera");
Genvid_DestroyStream("video");

この処理を行うことで、ライブ配信やエンコードに必要な一時バッファなど、指定されたストリームに関連する内部ストレージがすべて解放されます。

すでに破棄したストリームの streamID を使用すると、 GenvidStatus_InvalidState エラーが発生します。

両方のサブスクリプションルーチンに、サブスクライブ解除と同様のルーチンが存在します。

  1. GenvidStatus Genvid_Unsubscribe(const char *id, GenvidEventSummaryCallback callback, void *userData)
  2. GenvidStatus Genvid_UnsubscribeCommand(const char *id, GenvidCommandCallback callback, void *userData)
Genvid_Unsubscribe("some_event_id", &SomeEventCallback, nullptr);
Genvid_UnsubscribeCommand("some_command_id", &SomeCommandCallback, nullptr);

引数に nullptr を送信すると、そのコールバックの既存のコールバックと同じになります。

例えば、 SomeEventCallback() の関数を呼び出すために登録されたすべてのイベントコールバックの登録を解除するには、次のコマンドを使用します。

Genvid_Unsubscribe(nullptr, &SomeEventCallback, nullptr);

既存のすべてのコマンドコールバックのサブスクライブを解除するには、次のコマンドを使用します。

Genvid_UnsubscribeCommand(nullptr, nullptr, nullptr);

Genvid MILE SDK の使用が終ったら、 GenvidStatus Genvid_Terminate() を呼び出して API を終了します。

GenvidStatus gs = Genvid_Terminate();
if(gs != GenvidStatus_Success)
{
    return false;
}

API の終了後、次の呼び出しを行うため、API をもう一度初期化する必要があります。