You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

LiveKit React Native SDK双客户端音视频流收发异常问题

LiveKit React Native 音视频收发异常问题

问题描述

基于LiveKit示例App开发,已实现示例全部功能,成功连接到https://example.livekit.io/房间,能接收网页端音频,但无法读取视频流,也完全无法发送音频或视频。

重现步骤

  • 在index.js中添加以下代码:
import { registerRootComponent } from "expo";
import { registerGlobals } from "livekit-react-native";

import App from "./App";
registerRootComponent(App);
registerGlobals();
  • 在App.tsx中渲染以下组件(仅移除了屏幕共享和消息逻辑,其余与示例一致):
import { Participant, Room, Track } from "livekit-client";
import {
  useRoom,
  useParticipant,
  AudioSession,
  VideoView,
} from "livekit-react-native";
import { useEffect, useState } from "react";
import { Text, ListRenderItem, StyleSheet, FlatList, View } from "react-native";
import { ParticipantView } from "./ParticipantView";
import { RoomControls } from "./RoomControls";
import type { TrackPublication } from "livekit-client";

const App = () => {
  // Create a room state
  const [, setIsConnected] = useState(false);
  const [room] = useState(
    () =>
      new Room({
        publishDefaults: { simulcast: false },
        adaptiveStream: true,
      })
  );

  // Get the participants from the room
  const { participants } = useRoom(room);
  const url = "[hard-coded-url]";
  const token =
    "[hard-coded-token]";
  useEffect(() => {
    let connect = async () => {
      // If you wish to configure audio, uncomment the following:
      await AudioSession.configureAudio({
        android: {
          preferredOutputList: ["speaker"],
        },
        ios: {
          defaultOutput: "speaker",
        },
      });
      await AudioSession.startAudioSession();
      await room.connect(url, token, {});
      await room.localParticipant.setCameraEnabled(true);
      await room.localParticipant.setMicrophoneEnabled(true);
      await room.localParticipant.enableCameraAndMicrophone();
      console.log("connected to ", url);
      setIsConnected(true);
    };

    connect();
    return () => {
      room.disconnect();
      AudioSession.stopAudioSession();
    };
  }, [url, token, room]);
  // Setup views.
  const stageView = participants.length > 0 && (
    <ParticipantView participant={participants[0]} style={styles.stage} />
  );

  const renderParticipant: ListRenderItem<Participant> = ({ item }) => {
    return (
      <ParticipantView participant={item} style={styles.otherParticipantView} />
    );
  };

  const otherParticipantsView = participants.length > 0 && (
    <FlatList
      data={participants}
      renderItem={renderParticipant}
      keyExtractor={(item) => item.sid}
      horizontal={true}
      style={styles.otherParticipantsList}
    />
  );

  const { cameraPublication, microphonePublication } = useParticipant(
    room.localParticipant
  );

  return (
    <View style={styles.container}>
      {stageView}
      {otherParticipantsView}
      <RoomControls
        micEnabled={isTrackEnabled(microphonePublication)}
        setMicEnabled={(enabled: boolean) => {
          room.localParticipant.setMicrophoneEnabled(enabled);
        }}
        cameraEnabled={isTrackEnabled(cameraPublication)}
        setCameraEnabled={(enabled: boolean) => {
          room.localParticipant.setCameraEnabled(enabled);
        }}
        onDisconnectClick={() => {
          //   navigation.pop();
          console.log("disconnected");
        }}
      />
    </View>
  );
};

function isTrackEnabled(pub?: TrackPublication): boolean {
  return !(pub?.isMuted ?? true);
}
const styles = StyleSheet.create({
  container: {
    flex: 1,
    alignItems: "center",
    justifyContent: "center",
  },
  stage: {
    flex: 1,
    width: "100%",
  },
  otherParticipantsList: {
    width: "100%",
    height: 150,
    flexGrow: 0,
  },
  otherParticipantView: {
    width: 150,
    height: 150,
  },
});

export default App;
  • 使用Expo开发构建运行应用
  • 日志显示已连接,能听到远端参与者声音,但看不到视频,也无法发送任何声音
  • 若在useEffect中添加await room.localParticipant.enableCameraAndMicrophone();,会抛出以下错误:
Possible Unhandled Promise Rejection (id: 0):
Error: Not implemented.
getSettings@http://192.168.1.150:8081/index.bundle?platform=ios&dev=true&hot=false:103733:24
@http://192.168.1.150:8081/index.bundle?platform=ios&dev=true&hot=false:120307:109
generatorResume@[native code]
asyncGeneratorStep@http://192.168.1.150:8081/index.bundle?platform=ios&dev=true&hot=false:21908:26
_next@http://192.168.1.150:8081/index.bundle?platform=ios&dev=true&hot=false:21927:29
@http://192.168.1.150:8081/index.bundle?platform=ios&dev=true&hot=false:21932:14
tryCallTwo@http://192.168.1.150:8081/index.bundle?platform=ios&dev=true&hot=false:26656:9
doResolve@http://192.168.1.150:8081/index.bundle?platform=ios&dev=true&hot=false:26788:25
Promise@http://192.168.1.150:8081/index.bundle?platform=ios&dev=true&hot=false:26675:14
@http://192.168.1.150:8081/index.bundle?platform=ios&dev=true&hot=false:21924:25
@http://192.168.1.150:8081/index.bundle?platform=ios&dev=true&hot=false:120173:52
generatorResume@[native code]
asyncGeneratorStep@http://192.168.1.150:8081/index.bundle?platform=ios&dev=true&hot=false:21908:26
_next@http://192.168.1.150:8081/index.bundle?platform=ios&dev=true&hot=false:21927:29
tryCallOne@http://192.168.1.150:8081/index.bundle?platform=ios&dev=true&hot=false:26648:16
@http://192.168.1.150:8081/index.bundle?platform=ios&dev=true&hot=false:26729:27
@http://192.168.1.150:8081/index.bundle?platform=ios&dev=true&hot=false:27687:26
_callTimer@http://192.168.1.150:8081/index.bundle?platform=ios&dev=true&hot=false:27602:17
_callReactNativeMicrotasksPass@http://192.168.1.150:8081/index.bundle?platform=ios&dev=true&hot=false:27635:17
callReactNativeMicrotasks@http://192.168.1.150:8081/index.bundle?platform=ios&dev=true&hot=false:27799:44
__callReactNativeMicrotasks@http://192.168.1.150:8081/index.bundle?platform=ios&dev=true&hot=false:21006:46
@http://192.168.1.150:8081/index.bundle?platform=ios&dev=true&hot=false:20806:45
__guard@http://192.168.1.150:8081/index.bundle?platform=ios&dev=true&hot=false:20986:15
flushedQueue@http://192.168.1.150:8081/index.bundle?platform=ios&dev=true&hot=false:20805:21
flushedQueue@[native code]

预期行为

双客户端之间应能正常收发音视频流


解决方案

  1. 移除enableCameraAndMicrophone()调用
    这个方法在LiveKit React Native SDK中并未实现(从报错信息Error: Not implemented可确认),你已经调用了setCameraEnabled(true)和setMicrophoneEnabled(true),这两个方法已经足够启用本地音视频设备并发布流,无需额外调用enableCameraAndMicrophone()。

  2. 检查权限配置
    Expo环境下需要确保已配置相机和麦克风权限:

    • 在app.json中添加权限声明:
      "ios": {
        "infoPlist": {
          "NSCameraUsageDescription": "需要访问相机进行视频通话",
          "NSMicrophoneUsageDescription": "需要访问麦克风进行语音通话"
        }
      },
      "android": {
        "permissions": ["CAMERA", "RECORD_AUDIO"]
      }
      
    • 在代码中主动请求权限:
      import * as Permissions from 'expo-permissions';
      
      // 在connect函数开头添加权限请求
      const { status: cameraStatus } = await Permissions.askAsync(Permissions.CAMERA);
      const { status: micStatus } = await Permissions.askAsync(Permissions.MICROPHONE);
      if (cameraStatus !== 'granted' || micStatus !== 'granted') {
        alert('需要授予相机和麦克风权限才能使用');
        return;
      }
      
  3. 修复远端视频不显示问题
    确保ParticipantView组件正确渲染远端视频轨道:

    // ParticipantView示例实现
    import { VideoView } from 'livekit-react-native';
    import { useParticipant } from 'livekit-react-native';
    
    export const ParticipantView = ({ participant, style }) => {
      const { videoTrack } = useParticipant(participant);
      return videoTrack ? (
        <VideoView track={videoTrack} style={style} />
      ) : null;
    };
    
  4. 调整Room配置
    建议开启simulcast(移动端默认支持),优化视频发布配置:

    new Room({
      publishDefaults: { simulcast: true },
      adaptiveStream: true,
    })
    

内容的提问来源于stack exchange,提问作者Alaa Mady

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.08 21:25:25