映像レンダリングガイド

概要

Sora Flutter SDK での映像レンダリングの方法について説明します。

描画までの流れは次のとおりです。

  1. 映像の textureId を取得する
  • ローカル映像は LocalVideoTrack.textureId から textureId を取得する
  • リモート映像は SoraTrackEvent で受け取った RemoteMediaStreamTrack.textureId を使う
  1. 取得した textureId を Flutter の Texture に渡して描画する

イベント全体の一覧や SoraConnection.events の使い方は イベント をご確認ください。

TextureId を取得する

ローカル映像

ローカル映像を表示するには、まず送信用の MediaStream を用意します。 MediaStream の作成方法は メディアデバイスガイド をご確認ください。

ローカル映像の textureIdLocalVideoTrack.textureId ( Future<int> ) で取得します。

final stream = await MediaDevices.getUserMedia(
  const GetUserMediaOptions(audio: true, video: true),
);
final videoTrack = stream.getVideoTracks().first;
final textureId = await videoTrack.textureId;

ただし、 createExternalVideoTrack で生成した外部映像入力用の LocalVideoTracktextureId を返しません。詳細は 外部映像入力ガイド をご確認ください。

リモート映像

受信したリモート映像から textureId を取得する方法を説明します。 リモート映像を受信するまでの基本的な流れは 導入ガイド をご確認ください。また、 conn.events によりイベント購読しているものとします。

リモート映像は conn.eventsSoraTrackEvent で受け取ります。トラックは RemoteMediaStreamTrack として通知され、 kind == 'video' の場合のみ textureId が non-null になります。

final remoteTextureIds = <String, int>{};

conn.events.listen((event) {
  switch (event) {
    case SoraTrackEvent(:final track):
      final textureId = track.textureId;
      if (track.kind == 'video' && textureId != null) {
        setState(() {
          remoteTextureIds[track.trackId] = textureId;
        });
      }
    default:
      break;
  }
});

trackId は、複数リモートトラックを識別する際に利用できます。

remote track event の型や通知タイミングの詳細は イベント を参照してください。

Texture によるレンダリング

textureId を Flutter の Texture ウィジェットに渡してレンダリングします。リモートトラックの textureIdint? なので、 kind == 'video' を確認してから利用します。

Widget buildVideo(int textureId) {
  return Texture(textureId: textureId);
}

final localVideo = buildVideo(textureId);
final remoteVideo = buildVideo(track.textureId!);

複数のリモート映像を並べて表示する場合は、受信したトラックのリストを GridViewWrap などに流し込みます。

Widget buildRemoteVideos(Map<String, int> remoteTextureIds) {
  return GridView.count(
    crossAxisCount: 2,
    children: remoteTextureIds.values
        .map((textureId) => Texture(textureId: textureId))
        .toList(),
  );
}

削除されたリモートトラックの映像を取り除く

リモート側の切断等により SoraRemoveTrackEvent が通知された映像トラックの textureId は描画に使えなくなるため、対応する Texture をツリーから取り除きます。

// trackId をキーに textureId を管理するマップです
final remoteTextureIds = <String, int>{};

conn.events.listen((event) {
  switch (event) {
    case SoraTrackEvent(:final track):
      final textureId = track.textureId;
      if (track.kind == 'video' && textureId != null) {
        setState(() {
          remoteTextureIds[track.trackId] = textureId;
        });
      }
    // SoraRemoveTrackEvent で該当する trackId をリストから削除します
    case SoraRemoveTrackEvent(:final track):
      if (track.kind == 'video') {
        setState(() {
          // trackId をキーに管理すると、SoraRemoveTrackEvent を受けたタイミングで該当する Texture を自然に表示から外せます
          remoteTextureIds.remove(track.trackId);
        });
      }
    default:
      break;
  }
});

あわせて読むとよいページ