blackuy / react-native-twilio-video-webrtc

Twilio Video (WebRTC) for React Native
https://www.twilio.com/docs/video
MIT License
608 stars 403 forks source link

Multiple users not working (3 or more video conference) #326

Open tapannathvani opened 4 years ago

tapannathvani commented 4 years ago

Steps to reproduce

1.Installed application in 2 android device & 1 iPhone device with 3 different tokens and same room name with different identity

Expected behaviour

Each user can see other members videos

Actual behaviour

Only 2 person able to do video chat

Environment

react-native-twilio-video-webrtc

Version: npm version or "master"

slycoder commented 4 years ago

Do you have some example code you could share? Are you receiving participant callbacks for the third+ participants?

tapannathvani commented 4 years ago

Able to hear 3rd person voice but not able to see his video. Here is the App.js file code which we are using.


 * Sample React Native App
 * https://github.com/facebook/react-native
 *
 * @format
 * @flow
 */

import React, {Component} from 'react';
import {
  StyleSheet,
  Text,
  TextInput,
  View,
  Button,
  TouchableOpacity,
  Platform,
} from 'react-native';

import {
  TwilioVideoLocalView,
  TwilioVideoParticipantView,
  TwilioVideo,
} from 'react-native-twilio-video-webrtc';

class App extends Component {
  state = {
    isAudioEnabled: true,
    isVideoEnabled: true,
    status: 'disconnected',
    participants: new Map(),
    videoTracks: new Map(),
    roomName: 'Room1',
token:'<OUR 3 different tokens for each device>',
  };

  _onConnectButtonPress = () => {
    try {
      this.twilioRef.connect({
        roomName: this.state.roomName,
        accessToken: this.state.token,
      });
    } catch (error) {
      console.log(error);
    }

    this.setState({status: 'connecting'});
  };

  _onEndButtonPress = () => {
    this.twilioRef.disconnect();
  };

  _onMuteButtonPress = () => {
    this.twilioRef
      .setLocalAudioEnabled(!this.state.isAudioEnabled)
      .then((isEnabled) => this.setState({isAudioEnabled: isEnabled}));
  };

  _onFlipButtonPress = () => {
    this.twilioRef.flipCamera();
  };

  _onRoomDidConnect = () => {
    this.setState({status: 'connected'});
  };

  _onRoomDidDisconnect = ({roomName, error}) => {
    console.log('ERROR: ', error);

    this.setState({status: 'disconnected'});
  };

  _onRoomDidFailToConnect = (error) => {
    console.log('ERROR: ', error);

    this.setState({status: 'disconnected'});
  };

  _onParticipantAddedVideoTrack = ({participant, track}) => {
    console.log('onParticipantAddedVideoTrack: ', participant, track);

    this.setState({
      videoTracks: new Map([
        ...this.state.videoTracks,
        [
          track.trackSid,
          {participantSid: participant.sid, videoTrackSid: track.trackSid},
        ],
      ]),
    });
  };

  _onParticipantRemovedVideoTrack = ({participant, track}) => {
    console.log('onParticipantRemovedVideoTrack: ', participant, track);

    const videoTracks = this.state.videoTracks;
    videoTracks.delete(track.trackSid);

    this.setState({videoTracks: new Map([...videoTracks])});
  };

  setTwilioRef = (ref) => {
    this.twilioRef = ref;
  };

  render() {
    return (
      <View style={styles.container}>
        {this.state.status === 'disconnected' && (
          <View>
            <Text style={styles.welcome}>React Native Twilio Webrtc</Text>
            <TextInput
              style={styles.input}
              autoCapitalize="none"
              value={this.state.roomName}
              onChangeText={(text) => this.setState({roomName: text})}
            />
            <TextInput
              style={styles.input}
              autoCapitalize="none"
              value={this.state.token}
              onChangeText={(text) => this.setState({token: text})}
            />
            <Button
              title="Connect"
              style={styles.button}
              onPress={this._onConnectButtonPress}
            />
          </View>
        )}

        {this.state.status === 'connected' ||
        this.state.status === 'connecting' ? (
          <View style={styles.callContainer}>
            {this.state.status === 'connected' && (
              <View style={styles.remoteGrid}>
                {Array.from(
                  this.state.videoTracks,
                  ([trackSid, trackIdentifier]) => {
                    return (
                      <TwilioVideoParticipantView
                        style={styles.remoteVideo}
                        key={trackSid}
                        trackIdentifier={trackIdentifier}
                      />
                    );
                  },
                )}
              </View>
            )}
            <View style={styles.optionsContainer}>
              <TouchableOpacity
                style={styles.optionButton}
                onPress={this._onEndButtonPress}>
                <Text style={{fontSize: 12}}>End</Text>
              </TouchableOpacity>
              <TouchableOpacity
                style={styles.optionButton}
                onPress={this._onMuteButtonPress}>
                <Text style={{fontSize: 12}}>
                  {this.state.isAudioEnabled ? 'Mute' : 'Unmute'}
                </Text>
              </TouchableOpacity>
              <TouchableOpacity
                style={styles.optionButton}
                onPress={this._onFlipButtonPress}>
                <Text style={{fontSize: 12}}>Flip</Text>
              </TouchableOpacity>
              <TwilioVideoLocalView enabled={true} style={styles.localVideo} />
              <View />
            </View>
          </View>
        ) : null}

        <TwilioVideo
          ref={this.setTwilioRef}
          onRoomDidConnect={this._onRoomDidConnect}
          onRoomDidDisconnect={this._onRoomDidDisconnect}
          onRoomDidFailToConnect={this._onRoomDidFailToConnect}
          onParticipantAddedVideoTrack={this._onParticipantAddedVideoTrack}
          onParticipantRemovedVideoTrack={this._onParticipantRemovedVideoTrack}
        />
      </View>
    );
  }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: 'white',
  },
  callContainer: {
    flex: 1,
    position: 'absolute',
    bottom: 0,
    top: 0,
    left: 0,
    right: 0,
  },
  welcome: {
    fontSize: 30,
    textAlign: 'center',
    paddingTop: 40,
  },
  input: {
    height: 50,
    borderWidth: 1,
    marginRight: 70,
    marginLeft: 70,
    marginTop: 50,
    textAlign: 'center',
    backgroundColor: 'white',
  },
  button: {
    marginTop: 100,
  },
  localVideo: {
    flex: 1,
    width: 125,
    height: 200,
    position: 'absolute',
    right: 10,
    bottom: 400,
    borderRadius: 2,
    borderColor: '#4e4e4e',
  },
  remoteGrid: {
    flex: 1,
    flexDirection: 'row',
    flexWrap: 'wrap',
  },
  remoteVideo: {
    width: '100%',
    height: '100%',
  },
  optionsContainer: {
    position: 'absolute',
    left: 0,
    bottom: 0,
    right: 0,
    height: 100,
    // backgroundColor: "blue",
    flexDirection: 'row',
    alignItems: 'center',
    justifyContent: 'center',
  },
  optionButton: {
    width: 60,
    height: 60,
    marginLeft: 10,
    marginRight: 10,
    borderRadius: 100 / 2,
    backgroundColor: 'grey',
    justifyContent: 'center',
    alignItems: 'center',
  },
});

export default App;
tapannathvani commented 4 years ago

Hello Sir, Any update on this?

Balasnest commented 4 years ago

@tapannathvani Can you share your twilio console config? Are you using Peer-Peer or Group-Small Room? Check your participant limit first

tapannathvani commented 4 years ago

I have created a Room with different client identity (Created 3 tokens with different CI) and with the same Room name. I have used demo application. Room type is Group.

ahmadtech2 commented 4 years ago

Iam facing the same issue, following the same example, using Group room type, i was able to hear all connected users but unable to switch between users

slycoder commented 4 years ago

When the first participant joins can they be seen or do none of the participants show up? I'm trying to narrow down if this is a problem with the group chat or this is an issue with the views that we're using.

As a followup, if you can indeed see one remote participant, it would be interesting to know if you replicated that view if you would have two views of the remote participant or if one would be blank.

Another thing to check is the codec that's being used. I know there can be compatibility issues across different codecs in group rooms.

ahmadtech2 commented 4 years ago

When the first participant joins can they be seen or do none of the participants show up? I'm trying to narrow down if this is a problem with the group chat or this is an issue with the views that we're using.

As a followup, if you can indeed see one remote participant, it would be interesting to know if you replicated that view if you would have two views of the remote participant or if one would be blank.

Another thing to check is the codec that's being used. I know there can be compatibility issues across different codecs in group rooms.

when first participant joins he can be seen with no issues, after another one joins, each one can see a random one, lets say user 1 saw user 3 and user 2 saw user 1, yes it might be missing event to be added to show different participant, iam using the example provided in readme, and i will try duplicating the views, thank you

ahmadtech2 commented 4 years ago

When the first participant joins can they be seen or do none of the participants show up? I'm trying to narrow down if this is a problem with the group chat or this is an issue with the views that we're using. As a followup, if you can indeed see one remote participant, it would be interesting to know if you replicated that view if you would have two views of the remote participant or if one would be blank. Another thing to check is the codec that's being used. I know there can be compatibility issues across different codecs in group rooms.

when first participant joins he can be seen with no issues, after another one joins, each one can see a random one, lets say user 1 saw user 3 and user 2 saw user 1, yes it might be missing event to be added to show different participant, iam using the example provided in readme, and i will try duplicating the views, thank you

after i tried cloning the TwilioVideoParticipantView it worked, my issue was from the view (style hight width 100%) i was able to loop over videoTracks and see them all, thank you

ahmadtech2 commented 4 years ago

Able to hear 3rd person voice but not able to see his video. Here is the App.js file code which we are using.

 * Sample React Native App
 * https://github.com/facebook/react-native
 *
 * @format
 * @flow
 */

import React, {Component} from 'react';
import {
  StyleSheet,
  Text,
  TextInput,
  View,
  Button,
  TouchableOpacity,
  Platform,
} from 'react-native';

import {
  TwilioVideoLocalView,
  TwilioVideoParticipantView,
  TwilioVideo,
} from 'react-native-twilio-video-webrtc';

class App extends Component {
  state = {
    isAudioEnabled: true,
    isVideoEnabled: true,
    status: 'disconnected',
    participants: new Map(),
    videoTracks: new Map(),
    roomName: 'Room1',
token:'<OUR 3 different tokens for each device>',
  };

  _onConnectButtonPress = () => {
    try {
      this.twilioRef.connect({
        roomName: this.state.roomName,
        accessToken: this.state.token,
      });
    } catch (error) {
      console.log(error);
    }

    this.setState({status: 'connecting'});
  };

  _onEndButtonPress = () => {
    this.twilioRef.disconnect();
  };

  _onMuteButtonPress = () => {
    this.twilioRef
      .setLocalAudioEnabled(!this.state.isAudioEnabled)
      .then((isEnabled) => this.setState({isAudioEnabled: isEnabled}));
  };

  _onFlipButtonPress = () => {
    this.twilioRef.flipCamera();
  };

  _onRoomDidConnect = () => {
    this.setState({status: 'connected'});
  };

  _onRoomDidDisconnect = ({roomName, error}) => {
    console.log('ERROR: ', error);

    this.setState({status: 'disconnected'});
  };

  _onRoomDidFailToConnect = (error) => {
    console.log('ERROR: ', error);

    this.setState({status: 'disconnected'});
  };

  _onParticipantAddedVideoTrack = ({participant, track}) => {
    console.log('onParticipantAddedVideoTrack: ', participant, track);

    this.setState({
      videoTracks: new Map([
        ...this.state.videoTracks,
        [
          track.trackSid,
          {participantSid: participant.sid, videoTrackSid: track.trackSid},
        ],
      ]),
    });
  };

  _onParticipantRemovedVideoTrack = ({participant, track}) => {
    console.log('onParticipantRemovedVideoTrack: ', participant, track);

    const videoTracks = this.state.videoTracks;
    videoTracks.delete(track.trackSid);

    this.setState({videoTracks: new Map([...videoTracks])});
  };

  setTwilioRef = (ref) => {
    this.twilioRef = ref;
  };

  render() {
    return (
      <View style={styles.container}>
        {this.state.status === 'disconnected' && (
          <View>
            <Text style={styles.welcome}>React Native Twilio Webrtc</Text>
            <TextInput
              style={styles.input}
              autoCapitalize="none"
              value={this.state.roomName}
              onChangeText={(text) => this.setState({roomName: text})}
            />
            <TextInput
              style={styles.input}
              autoCapitalize="none"
              value={this.state.token}
              onChangeText={(text) => this.setState({token: text})}
            />
            <Button
              title="Connect"
              style={styles.button}
              onPress={this._onConnectButtonPress}
            />
          </View>
        )}

        {this.state.status === 'connected' ||
        this.state.status === 'connecting' ? (
          <View style={styles.callContainer}>
            {this.state.status === 'connected' && (
              <View style={styles.remoteGrid}>
                {Array.from(
                  this.state.videoTracks,
                  ([trackSid, trackIdentifier]) => {
                    return (
                      <TwilioVideoParticipantView
                        style={styles.remoteVideo}
                        key={trackSid}
                        trackIdentifier={trackIdentifier}
                      />
                    );
                  },
                )}
              </View>
            )}
            <View style={styles.optionsContainer}>
              <TouchableOpacity
                style={styles.optionButton}
                onPress={this._onEndButtonPress}>
                <Text style={{fontSize: 12}}>End</Text>
              </TouchableOpacity>
              <TouchableOpacity
                style={styles.optionButton}
                onPress={this._onMuteButtonPress}>
                <Text style={{fontSize: 12}}>
                  {this.state.isAudioEnabled ? 'Mute' : 'Unmute'}
                </Text>
              </TouchableOpacity>
              <TouchableOpacity
                style={styles.optionButton}
                onPress={this._onFlipButtonPress}>
                <Text style={{fontSize: 12}}>Flip</Text>
              </TouchableOpacity>
              <TwilioVideoLocalView enabled={true} style={styles.localVideo} />
              <View />
            </View>
          </View>
        ) : null}

        <TwilioVideo
          ref={this.setTwilioRef}
          onRoomDidConnect={this._onRoomDidConnect}
          onRoomDidDisconnect={this._onRoomDidDisconnect}
          onRoomDidFailToConnect={this._onRoomDidFailToConnect}
          onParticipantAddedVideoTrack={this._onParticipantAddedVideoTrack}
          onParticipantRemovedVideoTrack={this._onParticipantRemovedVideoTrack}
        />
      </View>
    );
  }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: 'white',
  },
  callContainer: {
    flex: 1,
    position: 'absolute',
    bottom: 0,
    top: 0,
    left: 0,
    right: 0,
  },
  welcome: {
    fontSize: 30,
    textAlign: 'center',
    paddingTop: 40,
  },
  input: {
    height: 50,
    borderWidth: 1,
    marginRight: 70,
    marginLeft: 70,
    marginTop: 50,
    textAlign: 'center',
    backgroundColor: 'white',
  },
  button: {
    marginTop: 100,
  },
  localVideo: {
    flex: 1,
    width: 125,
    height: 200,
    position: 'absolute',
    right: 10,
    bottom: 400,
    borderRadius: 2,
    borderColor: '#4e4e4e',
  },
  remoteGrid: {
    flex: 1,
    flexDirection: 'row',
    flexWrap: 'wrap',
  },
  remoteVideo: {
    width: '100%',
    height: '100%',
  },
  optionsContainer: {
    position: 'absolute',
    left: 0,
    bottom: 0,
    right: 0,
    height: 100,
    // backgroundColor: "blue",
    flexDirection: 'row',
    alignItems: 'center',
    justifyContent: 'center',
  },
  optionButton: {
    width: 60,
    height: 60,
    marginLeft: 10,
    marginRight: 10,
    borderRadius: 100 / 2,
    backgroundColor: 'grey',
    justifyContent: 'center',
    alignItems: 'center',
  },
});

export default App;

try editing remoteVideo: { width: '100%', height: '100%', }, with remoteVideo: { width: '50%', height: '50%', }, screen will split to 4