关于 react-native-moq
react-native-moq 是基于 moq-kit 的 React Native MoQ 绑定,供需要在移动应用中发布或播放实时媒体的开发者使用。它通过 React hooks 和命令式接口处理视频、音频及数据轨道,并连接 MoQ 中继。
主要功能
- 01连接 MoQ 中继并发现广播
- 02播放视频和音频广播
- 03通过摄像头与麦克风发布媒体
- 04发布和接收数据轨道
- 05提供 hooks 与命令式接口
适用场景
- 01在 React 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 中继发布和接收实时视频、音频和数据轨道,延迟低于 1 秒。基于 Software Mansion 的 moq-kit 原生库构建。
**要求:**React Native 新架构(Fabric + TurboModules)、iOS 16+、Android API 30+。
npm install react-native-moq
cd ios && pod install
可选播放器界面(全屏模态框、控件、音量滑块):
npm install react-native-moq-ui @react-native-vector-icons/material-icons
iOS 还需要在 Info.plist 的 UIAppFonts 下添加 MaterialIcons.ttf,然后再次运行 pod install。如果你要在 <VideoView> 上自行组合播放器 UI,可以跳过此软件包。
心智模型
- Session 是与 MoQ 中继的一个连接(
useSession(url))。它不会自动连接——需要自行调用session.connect()。一个 session 可同时用于订阅和发布。 - 订阅:
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)独立运行,不在进程内。 - 每个钩子都有不使用钩子的对应 API——有状态对象使用
create*(返回对象和destroy()),订阅钩子使用subscribe*(返回start()/stop())——详见 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 需要非空广播——请在仅当广播存在时才渲染的子组件中挂载它们。
快速入门 — 开始直播
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:')。媒体故障不会抛出异常。Session 仅在状态字符串中携带错误消息(state.slice(6));采集轨道和发布器还会公开lastError字段。播放器完全没有错误状态——应改为关注 session 和发布器状态。 publish()要求session.state === 'connected',否则发布器会直接进入error:session is not connected状态。请根据 session 状态控制开始直播按钮。- **使用
getSupportedVideoCodecs()/getSupportedAudioCodecs()检查编解码器支持情况。**在 Android 上,不受支持的编码器(通常是h265)会导致发布开始后悄然停止,且没有错误提示。默认使用h264/opus。 - 权限由宿主应用负责处理——在 Android 上请求 CAMERA/RECORD_AUDIO 权限,在 iOS 上添加 NSCameraUsageDescription/NSMicrophoneUsageDescription。预览画面为黑色通常是因为缺少权限。
<VideoView>不接受子元素(Android 原生视图不是 ViewGroup)。请将叠加层渲染为采用绝对定位的同级元素。- 采集钩子使用引用计数的设备单例——所有使用者共享同一个物理摄像头/麦克风;
flip()会影响所有使用者。挂载期间若要关闭硬件,请使用enabled: false,不要有条件地调用钩子。 - 广播路径相对于订阅前缀(在前缀
'live'下,广播live/test会显示为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