Socket
Socket
Sign inDemoInstall

@telnyx/video-react-native

Package Overview
Dependencies
10
Maintainers
10
Versions
3
Alerts
File Explorer

Advanced tools

Install Socket

Detect and block malicious and high-risk dependencies

Install

    @telnyx/video-react-native

Telnyx Video React Native SDK


Version published
Weekly downloads
65
increased by96.97%
Maintainers
10
Created
Weekly downloads
 

Readme

Source

Telnyx Video React Native

Getting Started

In this guide, you’ll learn how to get run and deploy Telnyx Meet

Just follow these steps:

  1. Sign up for a Telnyx Account
  2. Create an API KEY
  3. Create a Room ID
  4. Installation

Step 1: Sign Up for a Telnyx Mission Control Portal Account

Head to telnyx.com/sign-up to sign up for your free Telnyx account.

Once signed up you will have access to Telnyx Portal, where you can set up and manage your API KEY, and more.

Step 2: Create an API KEY

Go to API Keys section and click on Create API Key button. It will generate a key for you. Copy and save this key in a safe place and don't share it with anyone it is a sensitive value.

You need this API Key to consume the API https://api.telnyx.com/v2/rooms to manage your room ids.

create api key

Step 3: Create a Room ID

You should read this documentation video/Rooms to learn how to create a new video room id. When you get your roomId you can join in a video meet conference.

Step 4. Installation

Install the package with:

npm install @telnyx/video-react-native --save

In android/settings.gradle file add following code

   include ':react-native-webrtc'  
   project(':react-native-webrtc').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-webrtc/android')

In android/build.gradle file make minSdkVersion=24

In android/app/src/main/java/(package name)/MainApplication.java add following:

In import section add

    import com.oney.WebRTCModule.WebRTCModulePackage;

In React package section add

    packages.add(new WebRTCModulePackage());

In android/app/build.gradle file add

In dependency section add:

    implementation project(':react-native-webrtc') 

As long as you can import npm packages with a bundler like Webpack, you're ready to import Room and any other class required and begin.

You will also need some classes from react-native-webrtc such as RTCView which can be used to display a video stream:

import { Room, initialize, State } from '@telnyx/video-react-native';
import { RTCView, mediaDevices, MediaStream } from 'react-native-webrtc';

You will also need https://babeljs.io/docs/en/babel-plugin-proposal-async-generator-functions#installation to be able to use some of the async calls in the SDK.

Permissions

In order to use native mobile features such as internet or record audio, you need to enable permissions for both platforms. You can follow these guides: Android iOS

Usage

General usage is the same as the vanilla web JS video implementation which is described here

And then use a permission library such as react-native-permissions to verify that the permissions are enabled at runtime.

React Native Specific Usage

The key difference between the Web and React Native SDK is how we attach streams to a view. With React Native we are no longer using DOM elements, but rather an RTCView:

  const [localStream, setStream] = useState<string>('');

      ...
      
 const onPressPublish = async () => {
    try {
      let callerStream = await mediaDevices.getUserMedia({
        audio: true,
        video: true,
      });
      console.log('got local stream using getUserMedia...');

      // Get audio and video tracks from the MediaStream's
      // since the sdk works with MediaStreamTrack
      let callerAudioTrack = callerStream.getAudioTracks()[0];
      let callerVideoTrack = callerStream.getVideoTracks()[0];

      await room.addStream('self', {
        audio: callerAudioTrack,
        video: callerVideoTrack,
      });

      setStream(callerStream.toURL());
    } catch (e) {
      console.error("Unable to publish stream...");
    }
  };
  
  ....
  
  <SafeAreaView style={styles.localStreamBox}>
        {
          localStream ?
            <RTCView
              mirror={true}
              objectFit={'contain'}
              streamURL={localStream!}
              style={{ width: '100%', height: '100%' }}
              zOrder={1}
            /> : null
        }
      </SafeAreaView>

Full example:

Below is an adapted version of the following web example adapted for React Native with this library

 import * as React from 'react';

import { StyleSheet, View, Alert, Platform, StatusBar, SafeAreaView, Button } from 'react-native';
import { RTCView, mediaDevices, MediaStream } from 'react-native-webrtc';
import { useEffect, useState } from 'react';
import { Room, initialize, State } from 'telnyx-video-react-native';
import { FlatGrid } from 'react-native-super-grid';
import { requestMultiple, PERMISSIONS } from 'react-native-permissions';
import Config from "react-native-config";

//create .env file in root of example and store Room ID and API Key
let ROOM_ID = Config.ROOM_ID
let API_KEY = Config.API_KEY
export default function App() {
  const [localStream, setStream] = useState<string>('');
  const [room, setRoom] = useState<typeof Room>();
  const [participantStreamMaps, setParticipantStreamMaps] = useState<Map<String, MediaStream>>(new Map<string, MediaStream>())
  const updateStreamMap = (k: string, v: MediaStream) => {
    setParticipantStreamMaps(new Map(participantStreamMaps.set(k, v)));
  }
  const deleteFromStreamMap = (v: string) => {
    participantStreamMaps.delete(v)
    let map = new Map(participantStreamMaps)
    map.delete(v)
    setParticipantStreamMaps(new Map(map));
  }
  const [data, setData] = useState();
  const [isLoading, setLoading] = useState(true);

  useEffect(() => {
    if (API_KEY == undefined || ROOM_ID == undefined) {
      throw Error('Please create a .env file and add your ROOM_ID and API_KEY');
    }
    verifyPermissions();
    getToken();
  }, []);

  const getToken = async () => {
    const requestTokenUrl = `https://api.telnyx.com/v2/rooms/${ROOM_ID}/actions/generate_join_client_token`;
    var tokenReceived;
    try {
      const response = await fetch(requestTokenUrl, {
        body: '{"refresh_token_ttl_secs":3600,"token_ttl_secs":600}',
        headers: {
          Accept: 'application/json',
          Authorization: `Bearer ${API_KEY}`,
          'Cache-Control': 'no-cache',
          'Content-Type': 'application/json',
        },
        method: 'POST',
      });
      const json = await response.json();
      setData(json);
      tokenReceived = json;
    } catch (error) {
      console.error(error);
    } finally {
      setLoading(false);
      makeCall(tokenReceived.data.token);
    }
  };

  async function makeCall(token: string) {
    let room;
    console.log(`Token being provided: ${token}`);

    // Replace this with the client token you generated previously.
    const context = '{"id":99999,"username":"React Native User"}';

    room = await initialize({
      roomId: ROOM_ID,
      clientToken: token,
      context: context,
      logLevel: 'DEBUG',
    });
    setRoom(room);

    // you are connected to the room
    room.on("connected", (state) => {
      let receivedState = state as State 
      console.log(`connected to the room... ` + JSON.stringify(receivedState));
      
      // Once we are connected we can access the list of participants that are already connected to the room.
      const remoteParticipants = state.participants;
      remoteParticipants.forEach((item) => {
        const remoteParticipant = state.participants.get(item.participantId);
        console.log(`participant connected ` + item);
      });

      // We can also access the list of streams available and subscribe to them if need it.
      state.streams.forEach((stream) => {
        if (stream.participantId === room.getLocalParticipant().id) {
          return;
        }

        room.addSubscription(stream.participantId, stream.key, {
          audio: true,
          video: true,
        });
      });
    });

    // a remote participant has joined the room
    room.on("participant_joined", (participantId, state) => {
      const remoteParticipant = state.participants.get(participantId);
      console.log(`participant ${remoteParticipant.context} joined...`);
    });

    // a stream has been published to the room
    room.on("stream_published", async (participantId, streamKey, state) => {
      // ignore streams that are published by the local participant
      // we only care about remote stream from other remote participant
      let participant = state.participants.get(participantId);
      if (participant.origin === "local") {
        return;
      }

      // the remote stream is identified using the participantId and streamKey
      // you need to subscribe to a remote stream in order to access it's `MediaStreamTrack`s
      await room.addSubscription(participantId, streamKey, {
        audio: true,
        video: true
      });

      console.log(
        `subscription to the: ${participantId} ${streamKey} has been added...`
      );
    });

    // a subscription to a remote stream has started
    room.on("subscription_started", (participantId, streamKey, state) => {
      console.log(
        `subscription to the: ${participantId} ${streamKey} stream started...`
      );

      let receivedState = state as State 
      console.log(`Subscription started :: State .. ` + JSON.stringify(receivedState));

      // use a helper method to easily access a remote participants' stream
      let remoteStream = room.getParticipantStream(participantId, streamKey);

      let remoteMediaStream = new MediaStream([
        remoteStream.audioTrack,
        remoteStream.videoTrack
      ]);

      // Add participant stream from participant stream array 
      updateStreamMap(participantId, remoteMediaStream)
    });


    // a subscription to a remote stream has ended
    room.on("subscription_ended", (participantId, streamKey, state) => {
      console.log(
        `subscription to the: ${participantId} ${streamKey} stream ended...`
      );

      deleteFromStreamMap(participantId)
    });

    await room.connect();
  }

  const verifyPermissions = async () => {
    if (Platform.OS == 'android') {
      let perm = [
        PERMISSIONS.ANDROID.CAMERA,
        PERMISSIONS.ANDROID.READ_EXTERNAL_STORAGE,
        PERMISSIONS.ANDROID.RECORD_AUDIO,
        PERMISSIONS.ANDROID.WRITE_EXTERNAL_STORAGE,
      ];
      let permissionStatuses = await requestMultiple(perm);
      console.log('obj', permissionStatuses);
      const result = permissionStatuses[perm[0]];
      if (result !== 'granted') {
        Alert.alert(
          'Insufficient permissions!',
          'You need to grant camera and library access permissions to use this app.',
          [{ text: 'Okay' }],
        );
        return false;
      }
      return true;
    } else {
      let perm = [PERMISSIONS.IOS.CAMERA, PERMISSIONS.IOS.MICROPHONE];
      let permissionStatuses = await requestMultiple(perm);
      console.log('obj', permissionStatuses);
      const result = permissionStatuses[perm[0]];
      if (result !== 'granted') {
        Alert.alert(
          'Insufficient permissions!',
          'You need to grant camera and library access permissions to use this app.',
          [{ text: 'Okay' }],
        );
        return false;
      }
      return true;
    }
  };

  const onPressPublish = async () => {
    try {
      let callerStream = await mediaDevices.getUserMedia({
        audio: true,
        video: true,
      });
      console.log('got local stream using getUserMedia...');

      // Get audio and video tracks from the MediaStream's
      // since the sdk works with MediaStreamTrack
      let callerAudioTrack = callerStream.getAudioTracks()[0];
      let callerVideoTrack = callerStream.getVideoTracks()[0];

      await room.addStream('self', {
        audio: callerAudioTrack,
        video: callerVideoTrack,
      });

      setStream(callerStream.toURL());
    } catch (e) {
      console.error("Unable to publish stream...");
    }
  };

  return (
    <>
      <StatusBar barStyle="dark-content" />
      <View style={styles.box}>
        <Button
          title="Start"
          onPress={onPressPublish} />
      </View>
      {
        <FlatGrid
          data={Array.from(participantStreamMaps.values())}
          style={styles.gridView}
          itemDimension={130}
          spacing={10}
          renderItem={({ item }) =>
            <SafeAreaView style={styles.remoteStreamBox}>
              <RTCView
                mirror={false}
                objectFit={'contain'}
                streamURL={item.toURL()}
                style={{ width: '100%', height: '100%' }}
                zOrder={1}
              />
            </SafeAreaView>}
          keyExtractor={item => item.toURL()}
        />
      }
      <SafeAreaView style={styles.localStreamBox}>
        {
          localStream ?
            <RTCView
              mirror={true}
              objectFit={'contain'}
              streamURL={localStream!}
              style={{ width: '100%', height: '100%' }}
              zOrder={1}
            /> : null
        }
      </SafeAreaView>
    </>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    alignItems: 'center',
    justifyContent: 'center',
  },
  gridView: {
    marginTop: 10,
    flex: 1,
  },
  box: {
    width: 60,
    height: 60,
    marginVertical: 20,
  },
  localStreamBox: {
    width: 400,
    height: 300,
    marginVertical: 20,
  },
  remoteStreamBox: {
    width: 200,
    height: 125,
  },
  sectionContainer: {
    marginTop: 32,
    paddingHorizontal: 24,
  },
  sectionTitle: {
    fontSize: 24,
    fontWeight: '600',
  },
  sectionDescription: {
    marginTop: 8,
    fontSize: 18,
    fontWeight: '400',
  },
  highlight: {
    fontWeight: '700',
  },
});

Keywords

FAQs

Last updated on 12 Dec 2022

Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc