react-native-moq について
react-native-moq は moq-kit を基盤とする React Native 向け MoQ バインディングです。モバイルアプリで MoQ リレーに接続し、フックまたは命令型 API から映像・音声・データのトラックを送受信できます。
主な機能
- 01MoQ リレーへの接続とブロードキャスト検索
- 02映像・音声ブロードキャストの再生
- 03カメラとマイクからのメディア配信
- 04データトラックの送受信
- 05フックと命令型 API
活用シーン
- 01React Native アプリでライブ配信を視聴
- 02端末のカメラとマイクからメディアを配信
- 03クライアント間でデータメッセージを交換
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ software-mansion-labs/ skills --skill react-native-moqインストール後、Claude Code で/react-native-moqを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
references/custom-tracks.mdimperative.mdplayback.mdpublishing.md詳細
react-native-moq
Media over QUIC(MoQ)の React Native バインディングです。サブ秒の低遅延でライブ動画、音声、データのトラックを MoQ リレーに配信し、リレーから受信できます。Software Mansion の moq-kit ネイティブライブラリを基盤としています。
要件: React Native New Architecture(Fabric + TurboModules)、iOS 16 以降、Android API 30 以降。
npm install react-native-moq
cd ios && pod install
オプションのプレーヤー UI(全画面モーダル、コントロール、音量スライダー):
npm install react-native-moq-ui @react-native-vector-icons/material-icons
iOS では、Info.plist の UIAppFonts に MaterialIcons.ttf も追加し、再度 pod install を実行する必要があります。<VideoView> 上に独自のプレーヤー UI を構成する場合は、このパッケージを省略してください。
基本的な考え方
- Session は MoQ リレーへの 1 つの接続です(
useSession(url))。自動接続はしないため、自分でsession.connect()を呼び出してください。1 つのセッションで購読と配信の両方を行えます。 - 購読:
useBroadcasts(session, prefix)でパスプレフィックス配下のライブブロードキャストを一覧表示し、BroadcastInfoを選択して、useVideoPlayer/useAudioPlayerを使い、<VideoView player={player}>でレンダリングします。生メディアを扱う方法として、useAudioChunks(エンコード済みまたは PCM を JS に渡す)やuseDataMessages(文字列ペイロード)もあります。 - 配信: キャプチャフックでトラックを生成する(
useCamera、useMicrophone、useMultiCamera)か、自分で生成し(useDataTrack、useAudioSource、useVideoSource)、usePublisher(session).publish({ path, tracks })を呼び出します。画面共有(useScreenBroadcast)は別プロセスで動作します。 - すべてのフックには、フックを使わない代替手段があります。状態を持つものにはオブジェクトと
destroy()を返すcreate*、購読フックにはstart()/stop()を返すsubscribe*があります。references/imperative.md を参照してください。 - オブジェクトはリアクティブな状態(
session.state、publisher.state、player.isPlayingなど)を公開し、変更時にフックが再レンダリングされます。addListenerまたはuseEvent/useEventListenerヘルパーを使って手動で購読することもできます。
クイックスタート — 視聴
function Watch() {
const session = useSession('https://relay.example.com', (s) => s.connect());
const broadcasts = useBroadcasts(session, ''); // '' = all paths
return broadcasts.map((b) => <BroadcastPlayer key={b.path} broadcast={b} />);
}
function BroadcastPlayer({ broadcast }: { broadcast: BroadcastInfo }) {
const player = useVideoPlayer(broadcast, (p) => p.play());
return <VideoView player={player} style={{ width: '100%', aspectRatio: 16 / 9 }} />;
}
useVideoPlayer / useAudioPlayer は null ではないブロードキャストを必要とするため、ブロードキャストが存在する場合にのみレンダリングされる子コンポーネント内でマウントしてください。
クイックスタート — ライブ配信
const session = useSession(url, (s) => s.connect());
const camera = useCamera();
const microphone = useMicrophone();
const publisher = usePublisher(session);
<PublisherView camera={camera} style={styles.preview} />
// when session.state === 'connected':
publisher.publish({ path: 'live/test', tracks: [camera, microphone] });
重要なルール
- エラーは例外ではなく文字列です。 状態は
'connected' | 'error:...'のようなユニオンです。state.startsWith('error:')で確認してください。メディアの失敗時に例外がスローされることはありません。セッションではメッセージは状態文字列にのみ含まれます(state.slice(6))。キャプチャトラックとパブリッシャーには、さらにlastErrorフィールドがあります。プレーヤーにはエラーを確認する手段がないため、セッションとパブリッシャーの状態を確認してください。 publish()を呼び出すにはsession.state === 'connected'が必要です。 そうでない場合、パブリッシャーはただちにerror:session is not connectedになります。セッションの状態に応じてライブ配信ボタンを有効にしてください。getSupportedVideoCodecs()/getSupportedAudioCodecs()でコーデックを確認してください。 Android では、サポートされていないエンコーダー(多くの場合h265)を使うと、エラーなしで配信が開始されたあと、ひそかに停止します。デフォルトではh264/opusを使用してください。- 権限の設定はホストアプリ側で行います。 Android では CAMERA / RECORD_AUDIO をリクエストし、iOS では NSCameraUsageDescription / NSMicrophoneUsageDescription を追加してください。プレビューが黒い場合、通常は権限が不足しています。
<VideoView>は子要素を受け取りません(Android のネイティブビューは ViewGroup ではありません)。オーバーレイは絶対位置指定した兄弟要素としてレンダリングしてください。- キャプチャフックは参照カウントされるデバイスシングルトンです。 すべてのコンシューマーが同じ物理カメラ/マイクを共有し、
flip()はすべてのコンシューマーに影響します。フックを条件付きで呼び出すのではなく、マウントしたままハードウェアをオフにするにはenabled: falseを使用してください。 - ブロードキャストのパスは購読プレフィックスからの相対パスです。 (ブロードキャスト
live/testは、プレフィックス'live'の下ではpath: 'test'として表示されます。)完全なパスを確認するには''を購読してください。一覧に表示されたブロードキャストを再生できず、リレーエラーcode=13NotFound が発生する場合、パスとプレフィックスが一致していません。 - データトラックはカタログに含まれません。 パブリッシャーとサブスクライバーは、別途トラック名について合意する必要があります(デフォルトは
'data')。 - アイドル状態の iOS マイクキャプチャは、オーディオセッションを
playAndRecordに保持するため、他のオーディオライブラリを妨げることがあります(insufficientPriority)。配信していないときは、マイクを無効にしてください(enabled: false)。
リファレンス
| タスク | 参照 |
|---|---|
セッション、ブロードキャストの検出、動画/音声の再生、<VideoView>、統計情報、トラックの切り替え、イベント、react-native-moq-ui | references/playback.md |
| カメラ、マルチカメラ、マイク、パブリッシャーのライフサイクル、画面のブロードキャスト、コーデックのクエリ | references/publishing.md |
| データトラックとメッセージ、JS への音声チャンク、自前の音声(PCM)と動画(フレームバッファー)の送信 | references/custom-tracks.md |
React を使用しない方法:create* ハンドル、subscribe* 関数、クリーンアップ | references/imperative.md |
コメント
Markdown 対応