イベント¶
概要¶
Sora Flutter SDK のイベントは、主に Stream<SoraConnectionEvent> と Stream<SoraDebugEvent> で提供されます。
Stream<SoraConnectionEvent> では、接続状態、リモートトラックの追加・削除、シグナリング、DataChannel (通知・メッセージング・RPC 等)、タイムアウトを購読できます。
Stream<SoraDebugEvent> では、構造化されたログとタイムラインを購読できます。
統合イベント stream¶
Stream<SoraConnectionEvent> は統合イベント stream です。イベント型ごとに switch で分岐して処理します。
conn.events.listen((event) {
switch (event) {
case SoraConnectionStateChangedEvent(:final state):
print('state: $state');
case SoraConnectionErrorEvent(:final code, :final message):
print('error: ${code ?? 'unknown'} ${message ?? ''}');
case SoraTrackEvent(:final track):
print('track added: ${track.trackId}');
case SoraRemoveTrackEvent(:final track):
print('track removed: ${track.trackId}');
case SoraNotifyEvent(:final message):
print('notify: $message');
case SoraPushEvent(:final message):
print('push: $message');
case SoraSwitchedEvent(:final message):
print('switched: $message');
case SoraSignalingMessageEvent(:final event):
print('signaling: ${event.transportType} ${event.direction}');
case SoraDataChannelOpenEvent(:final event):
print('datachannel open: ${event.label}');
case SoraDataChannelMessageEvent(:final message):
print('message: ${message.label}');
case SoraTimeoutEvent():
print('timeout');
}
});
接続状態の変更¶
SoraConnectionStateChangedEvent は接続状態が変わったときに通知されます。
conn.events.listen((event) {
if (event case SoraConnectionStateChangedEvent(:final state)) {
switch (state) {
case SoraConnectingState():
print('connecting');
case SoraConnectedState():
print('connected');
case SoraDisconnectedState(:final closeInfo):
print('disconnected');
if (closeInfo != null) {
print('close code: ${closeInfo.code}');
print('close reason: ${closeInfo.reason}');
}
}
}
});
通知される状態は次の 3 種類です。
SoraConnectingStateSoraConnectedStateSoraDisconnectedState
SoraConnectingState¶
接続処理の開始後、シグナリング接続の確立に入ったタイミングで通知されます。
conn.events.listen((event) {
if (event case SoraConnectionStateChangedEvent(state: SoraConnectingState())) {
print('connecting');
}
});
SoraConnectedState¶
Sora との PeerConnection が接続済になったタイミングで通知されます。
conn.events.listen((event) {
if (event case SoraConnectionStateChangedEvent(state: SoraConnectedState())) {
print('connected');
}
});
SoraDisconnectedState¶
Sora から切断したタイミングで通知されます。
closeInfo を持つ場合は、切断時の close code と reason を参照できます。
conn.events.listen((event) {
if (event case SoraConnectionStateChangedEvent(
state: SoraDisconnectedState(:final closeInfo),
)) {
print('disconnected');
if (closeInfo != null) {
print('close code: ${closeInfo.code}');
print('close reason: ${closeInfo.reason}');
}
}
});
接続エラー¶
接続エラーは SoraConnectionErrorEvent で通知されます。
conn.events.listen((event) {
if (event case SoraConnectionErrorEvent(:final code, :final message)) {
print('connection error: ${code ?? 'unknown'} ${message ?? ''}');
}
});
code にはエラー種別が、 message にはエラーの詳細が含まれます。
どちらも null になる可能性があるため、利用の際は null チェックを行ってください。
code には、たとえば次のような値が入ります。
event_channel_errorwebsocket_errorconnection_timeoutdisconnect_timeoutsignaling_candidate_timeoutoffer_invalid
track¶
リモートトラックが追加されたときは SoraTrackEvent が通知されます。
トラックは RemoteMediaStreamTrack として渡され、 kind で音声か映像かを判別できます。
kind == 'audio': 音声トラック (textureIdはnull)kind == 'video': 映像トラック (textureIdは non-null)
conn.events.listen((event) {
if (event case SoraTrackEvent(:final track)) {
if (track.kind == 'audio') {
print('audio track added: ${track.trackId}');
} else {
print('video track added: ${track.trackId}');
print('textureId: ${track.textureId}');
}
}
});
RemoteMediaStreamTrack のフィールドは以下の通りです。
trackId: トラック IDkind:audioまたはvideoconnectionId: Sora のconnection_idtextureId:kind == 'video'の場合のみ値を取得できます
映像トラックの追加イベントでは、 textureId をそのまま Texture に渡せます。
if (event case SoraTrackEvent(:final track) when track.kind == 'video') {
return Texture(textureId: track.textureId!);
}
removetrack¶
リモートトラックが削除されたときは SoraRemoveTrackEvent が通知されます。
conn.events.listen((event) {
if (event case SoraRemoveTrackEvent(:final track)) {
print('track removed: ${track.trackId}');
}
});
削除イベントでも追加イベント時と同様に RemoteMediaStreamTrack 型となります。UI 側は通常 trackId で対象を特定して除去します。
接続単位でトラックを扱いたい場合は、 SoraConnection.remoteMediaStreams も利用できます。 connectionId をキーに RemoteMediaStream が入り、 audioTrack / videoTrack にそれぞれのトラックが格納されます。
notify¶
Sora からシグナリング通知を受け取ったときは SoraNotifyEvent が通知されます。
Sora のシグナリング通知の詳細は https://sora-doc.shiguredo.jp/SIGNALING_NOTIFY をご確認ください。
conn.events.listen((event) {
if (event case SoraNotifyEvent(:final message)) {
print('notify: $message');
}
});
connection.created などの通知をここで受け取ることができます。
push¶
Sora からのプッシュ通知を受け取ったときは SoraPushEvent が通知されます。
conn.events.listen((event) {
if (event case SoraPushEvent(:final message)) {
print('push: $message');
}
});
switched¶
シグナリングが WebSocket から DataChannel に切り替わったときは SoraSwitchedEvent が通知されます。
conn.events.listen((event) {
if (event case SoraSwitchedEvent(:final message)) {
print('switched: $message');
}
});
timeout¶
WebSocket の close reason が TIMEOUT のときは SoraTimeoutEvent が通知されます。
conn.events.listen((event) {
if (event case SoraTimeoutEvent()) {
print('timeout');
}
});
message¶
DataChannel を利用したリアルタイムメッセージング機能でメッセージを受信したときは SoraDataChannelMessageEvent が通知されます。
conn.events.listen((event) {
if (event case SoraDataChannelMessageEvent(:final message)) {
print('label: ${message.label}');
print('data: ${message.data}');
}
});
datachannel¶
DataChannel が利用可能になったときは SoraDataChannelOpenEvent が通知されます。
conn.events.listen((event) {
if (event case SoraDataChannelOpenEvent(:final dataChannel)) {
print('label: ${dataChannel.label}');
print('direction: ${dataChannel.direction}');
}
});
メッセージング機能を使う場合は、このイベントを送信可能の目安として扱えます。
signaling¶
シグナリングメッセージの送受信を確認したいときは SoraSignalingMessageEvent を利用します。
conn.events.listen((event) {
if (event case SoraSignalingMessageEvent(:final signaling)) {
print('${signaling.transportType} ${signaling.direction}');
print(signaling.data);
}
});
transportType は websocket または datachannel です。
direction は sent または received です。
data には、シグナリングメッセージの内容がそのまま入ります。 offer / answer / candidate などの内容を確認することができます。
デバッグイベント stream¶
conn.debugEvents はデバッグイベント専用 stream です。構造化された log と timeline を受け取りたい場合に利用します。
conn.debugEvents.listen((event) {
switch (event) {
case SoraLogDebugEvent(:final event):
print('${event.title}: ${event.message}');
case SoraTimelineDebugEvent(:final event):
print('${event.logType.value} ${event.type}');
print(event.data);
}
});
log¶
SDK の構造化ログは SoraLogDebugEvent で受け取ることができます。
conn.debugEvents.listen((event) {
if (event case SoraLogDebugEvent(:final log)) {
print('${log.title}: ${log.message}');
}
});
timeline¶
タイムラインの構造化ログは SoraTimelineDebugEvent で受け取ることができます。
conn.debugEvents.listen((event) {
if (event case SoraTimelineDebugEvent(:final timeline)) {
print('${timeline.logType.value} ${timeline.type}');
print(timeline.data);
}
});
SoraTimelineEvent では、主に次の情報を参照します。
type: イベント種別logType:websocket/datachannel/peerconnection/soradata: イベントの詳細データdataChannelId: DataChannel に紐づく場合の IDdataChannelLabel: DataChannel に紐づく場合の label
接続確立後の識別子¶
offer を受信すると、次の getter がサーバーから割り当てられた値で更新されます。
connectionIdserverClientIdbundleIdsessionId
接続前や offer 未到達のときは null です。RPC のパラメータ組み立てなどで利用できます。
イベント購読の終了¶
conn.events や conn.debugEvents を購読した場合は、 conn.dispose() の前に購読を解除してください。
late final StreamSubscription<SoraConnectionEvent> eventSubscription;
late final StreamSubscription<SoraDebugEvent> debugEventSubscription;
void setup(SoraConnection conn) {
eventSubscription = conn.events.listen((event) {
// イベント処理
});
debugEventSubscription = conn.debugEvents.listen((event) {
// debug event 処理
});
}
Future<void> dispose(SoraConnection conn) async {
await eventSubscription.cancel();
await debugEventSubscription.cancel();
await conn.dispose();
}