エンジン統合¶
統合¶
Genvid SDK API は、C: genvid.h
で記述される単一のヘッダファイルで構成されます。SDK を統合するには、ヘッダファイルをインクルードし、適切な共有ライブラリを追加する必要があります。
- コンパイル環境のインクルードパスに
genvid.h
を追加します。
- 共有ライブラリの適切なバージョンにリンクします。
- Genvid SDK には、Windows 用 32 ビット、64 ビットの両バージョンが含まれています。
- ゲームと一緒に、対応する DLL をデプロイします。
- 通常は、ゲームの実行ファイルと一緒に、Genvid.dll をコピーします。
- 処理がうまくいくことを確認します。
- すべての Genvid SDK メソッドが返す
GenvidStatus
で、処理が適切に行われているかを判断できます。また、const char* Genvid_StatusToString(const GenvidStatus status)
を使用して、enum 値を const char* に変換することもできます。
初期化¶
他のルーチンを呼び出す前に、 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 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;
}
データをストリームに送信する前に、設定が必要なパラメータがいくつか存在します。
パラメータの設定には、次のような関数を使用します。
GenvidStatus Genvid_SetParameterInt(const char *streamID, const char *paramKey, int *paramValue)
GenvidStatus Genvid_SetParameterFloat(const char *streamID, const char *paramKey, float *paramValue)
GenvidStatus Genvid_SetParameterPointer(const char *streamID,const char *paramKey, void *paramValue)
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 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 SDK は、オーディオストリームを自動キャプチャします。自動キャプチャを有効にするには、 Audio.Source.WASAPI
のパラメータに 1 を設定します。
GenvidStatus gs = Genvid_SetParameterInt("audio", "Audio.Source.WASAPI", 1);
if(gs != GenvidStatus_Success)
{
return false;
}
GENVID_AUDIO_DEVICE
環境変数は、使用するオーディオデバイスを定義する文字列を保持します。ローカルモードでは、デフォルトでは定義されませんが、クラウド構成では 「CABLE Input」 に定義されるため、通常はこれが使用されます。指定したデバイスが見つからない場合、デフォルトのオーディオエンドポイントが使用されます。
オーディオのフレームレートは、ビデオソースの設定値と同じ値に設定することを推奨します。
オーディオ自動キャプチャが有効になっている場合、デフォルトのミキシングフォーマットとサンプリングレートが使用されます。デフォルトでは、Windows は、48 kHz のステレオ浮動小数点数サンプルを使用します。
自動キャプチャ (現在、Unity engine でサポート) を使用しないでキャプチャすることもできます。データ送信前に、オーディオストリームに 3 つのパラメータを設定する必要があります。
audio.rate
audio.format
audio.channels
以下の表は、主要なストリームパラメータです。
注釈
パラメータキーは大文字、小文字を区別しません。
キー | 型 | サポートするメソッド | 説明 | デフォルト |
---|---|---|---|---|
framerate |
フロート | set と get | フレームレートを指定します。 | 30 |
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 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 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()
を明示的に呼び出す必要があります。
自動キャプチャ はアクティブにするだけで動作する、最も簡単な方法です。
オーディオデータのストリーミングの使用や設定方法については、 共通パラメータ を参照してください。
長所 | 短所 |
---|---|
オーディオキャプチャシステムは、SDK に実装済み | すべてのオーディオデータ (スピーカー音声、入力音声、マイク音声など) をキャプチャ |
自動オーディオ設定 (フォーマット、レート、チャンネル) | |
ゲームエンジンに左右されない |
長所 | 短所 |
---|---|
ゲームエンジンに左右されない | ゲーム側でのオーディオキャプチャの実行が必要 |
オーディオデータストリームの制御 | |
ローカルモードでの音声の問題を回避 |
ビデオストリーミング¶
レンダリングされたフレームが準備できたら、 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 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()
を使用しています。
注釈
イベントが存在する場合、 GenvidStatus
は GenvidStatus_Success
を返します。イベントが存在しない場合は、 GenvidStatus_ConnectionTimeout
が戻ります。
終了¶
ストリームの処理が完了したら、 GenvidStatus Genvid_DestroyStream(const char *streamID)
と適切な streamID
で、ストリームの割り当てを解除できます。
Genvid_DestroyStream("game.player");
Genvid_DestroyStream("came.camera");
Genvid_DestroyStream("video");
この処理を行うことで、ストリーミングやエンコードに必要な一時バッファなど、指定されたストリームに関連する内部ストレージがすべて解放されます。
すでに破棄したストリームの streamID
を使用すると、 GenvidStatus_InvalidState
エラーが発生します。
両方のサブスクリプションルーチンに、サブスクライブ解除と同様のルーチンが存在します。
GenvidStatus Genvid_Unsubscribe(const char *id, GenvidEventSummaryCallback callback, void *userData)
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 SDK の使用が終ったら、 GenvidStatus Genvid_Terminate()
を呼び出して API を終了します。
GenvidStatus gs = Genvid_Terminate();
if(gs != GenvidStatus_Success)
{
return false;
}
API の終了後、次の呼び出しを行うため、API をもう一度初期化する必要があります。