Skip to content

[Bug]: Swift runtime failure: force unwrapped a nil value #114

@R-qanawati

Description

@R-qanawati

Version

v2.0.2

Which operating systems have you used?

  • Android
  • iOS

Environment that reproduces the issue

Trying to start a stream with the example setup

Image

I have also changed the node modules package to do the post-install patch on RNLiveStreamView.mm

I have also attempted to use facebooks rtmps with my stream key but without any luck.

I've tried different audio/video rates and resolutions without any luck.

Is it reproducible in the example application?

Yes

RTMP Server

rtmp://broadcast.api.video/s

Reproduction steps

// @ts-ignore
import { ApiVideoLiveStreamView } from "@api.video/react-native-livestream";
import { useCameraPermissions, useMicrophonePermissions } from "expo-camera";
import React, { useRef, useState } from "react";
import {
  Alert,
  Platform,
  StyleSheet,
  Text,
  TouchableOpacity,
  View,
} from "react-native";

export default function Stream() {
  const [cameraPermission, requestCameraPermission] = useCameraPermissions();
  const [micPermission, requestMicPermission] = useMicrophonePermissions();

  const [streaming, setStreaming] = useState(false);
  const [camera, setCamera] = useState<"front" | "back">("back");
  const [audioMuted, setAudioMuted] = useState(false);

  const ref = useRef<any>(null);
  const isAndroid = Platform.OS === "android";

  const STREAM_KEY = "";
  const RTMP_ENDPOINT = `rtmp://broadcast.api.video/s`;

  if (!cameraPermission || !micPermission) {
    return (
      <View style={styles.center}>
        <Text style={styles.text}>Checking permissions…</Text>
      </View>
    );
  }

  if (!cameraPermission.granted || !micPermission.granted) {
    return (
      <View style={styles.center}>
        <Text style={styles.text}>Camera & microphone access needed</Text>
        <TouchableOpacity
          style={styles.button}
          onPress={async () => {
            await requestCameraPermission();
            await requestMicPermission();
          }}
        >
          <Text style={styles.buttonText}>Grant Permissions</Text>
        </TouchableOpacity>
      </View>
    );
  }

  const handleStreaming = (): void => {
    if (streaming) {
      ref.current?.stopStreaming();
      setStreaming(false);
    } else {
      ref.current
        ?.startStreaming(STREAM_KEY, RTMP_ENDPOINT) 
        .then((success: boolean) => {
          if (success) {
            console.log("Streaming started successfully");
            setStreaming(true);
          } else {
            console.log("Streaming failed to initialize");
            setStreaming(false);
          }
        })
        .catch((e: any) => {
          console.error("Failed to start streaming: ", e);
          Alert.alert("Streaming Error", `Failed to start: ${e.message || e}`);
          setStreaming(false);
        });
    }
  };

  const handleCamera = (): void => {
    if (camera === "back") {
      setCamera("front");
    } else {
      setCamera("back");
    }
  };

  return (
    <View style={styles.container}>
      <ApiVideoLiveStreamView
        style={styles.livestreamView}
        ref={ref}
        camera={camera}
        video={{
          bitrate: 500000,
          fps: 30,
          resolution: "360p",
        }}
        audio={{
          bitrate: 44100,
          sampleRate: 48000,
          isStereo: true,
        }}
        isMuted={audioMuted}
        enablePinchedZoom={true}
        onConnectionSuccess={() => {
          console.log("✅ Connection successful");
        }}
        onConnectionFailed={(reason: string) => {
          console.log("❌ Connection failed:", reason);
          Alert.alert("Connection Failed", reason);
          setStreaming(false);
        }}
        onDisconnect={() => {
          console.log("🔌 Disconnected");
          setStreaming(false);
        }}
      />

      <View style={[styles.buttonContainer, { bottom: isAndroid ? 20 : 40 }]}>
        <TouchableOpacity style={styles.streamButton} onPress={handleStreaming}>
          <Text style={styles.streamText}>
            {streaming ? "Stop Streaming" : "Start Streaming"}
          </Text>
        </TouchableOpacity>
      </View>

      <View
        style={[
          styles.buttonContainer,
          { bottom: isAndroid ? 20 : 40, left: 20 },
        ]}
      >
        <TouchableOpacity
          style={styles.iconButton}
          onPress={() => setAudioMuted(!audioMuted)}
        >
          <Text style={styles.iconText}>{audioMuted ? "🔇" : "🎤"}</Text>
        </TouchableOpacity>
      </View>

      <View
        style={[
          styles.buttonContainer,
          { bottom: isAndroid ? 20 : 40, right: 20 },
        ]}
      >
        <TouchableOpacity style={styles.iconButton} onPress={handleCamera}>
          <Text style={styles.iconText}>🔄</Text>
        </TouchableOpacity>
      </View>
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: "black",
  },
  livestreamView: {
    flex: 1,
    backgroundColor: "black",
    alignSelf: "stretch",
  },
  center: {
    flex: 1,
    justifyContent: "center",
    alignItems: "center",
    backgroundColor: "black",
    padding: 20,
  },
  text: {
    color: "white",
    fontSize: 16,
    textAlign: "center",
    marginBottom: 20,
  },
  button: {
    backgroundColor: "#0A84FF",
    paddingHorizontal: 30,
    paddingVertical: 15,
    borderRadius: 25,
  },
  buttonText: {
    color: "white",
    fontSize: 16,
    fontWeight: "600",
  },
  buttonContainer: {
    position: "absolute",
    alignSelf: "center",
  },
  streamButton: {
    backgroundColor: "#0A84FF",
    paddingHorizontal: 40,
    paddingVertical: 15,
    borderRadius: 25,
  },
  streamText: {
    color: "white",
    fontSize: 18,
    fontWeight: "600",
  },
  iconButton: {
    backgroundColor: "rgba(0,0,0,0.5)",
    width: 60,
    height: 60,
    borderRadius: 30,
    justifyContent: "center",
    alignItems: "center",
  },
  iconText: {
    fontSize: 24,
  },
});

Expected result

Stream starts successfully

Actual result

The app just freezes and crashes soon as i hit start stream.

Additional context

"@api.video/react-native-livestream": "^2.0.2",
"expo": "~54.0.27",
"react-native": "0.81.5",

Relevant logs output

Thread 1: Swift runtime failure: force unwrapped a nil value

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions