1

I am building a Java Springboot and react platform with twilio-video 2.27.0 - to allow to logged in members to video chat to each other.

enter image description here

I am getting what could look like a malfunction if its not fixed - that when leaving the room - the web cam light remains on -- I've tried to follow various references but nothing seems to work - the web cam light only stops on a hard refresh.

Twilio Video :How to destroy video room when user who created it leaves it?

Twilio room does not disconnect / Webcam LED remains on

track.stop is not turning the camera off anymore

enter image description here

I've tried stopping tracks, unpublishing, disable etc..

Also I get an error if a user clicks off the page without "leaving the room" and then they try and join the conference again - its like the room becomes unusable and a conference between them cant come back - the only way is to leave the room and re-create it again


import React, { Component } from 'react';
import Video from 'twilio-video';
import Button from '@mui/material/Button';
//import TextField from '@mui/material/TextField';
import { getToken, getUserDetails } from '../_globals/UserFunctions/UserFunctions';

class VideoChat extends Component {
  constructor(props) {
    super(props);
  
    this.state = {
      identity: "",
      roomId: null,
      username: '',
      localMediaAvailable: true,
      hasJoinedRoom: false,
      remoteMediaAvailable: false,
      remoteTracks: []
    };
  
    this.joinRoom = this.joinRoom.bind(this);
    this.leaveRoom = this.leaveRoom.bind(this);
    this.handleUsernameChange = this.handleUsernameChange.bind(this);
    this.handleRoomChange = this.handleRoomChange.bind(this);

    this.localMediaRef = React.createRef();
    this.remoteMediaRef = React.createRef();    
  }  

  handleUsernameChange(event) {
    this.setState({ username: event.target.value });
  }
  handleRoomChange(event) {
    this.setState({ roomId: event.target.value });
  }
  
  startComponent() {
    const userId = getUserDetails().id;
    fetch(`http://localhost:9000/api/twilio/token?userId=${userId}`, {
      headers: {
        'Authorization': 'Bearer ' + getToken()
        }})
      .then(res => res.json())
      .then(data => {
        Video.connect(data.token, { name: this.state.roomId }).then(this.joinRoom, error => console.error(`Unable to connect to Room: ${error.message}`));
        this.setState({ identity: userId });
      });
  }

  componentWillUnmount() {
    if (this.state.room) {
      this.state.room.disconnect();
    }
  }

  joinRoom(room) {
    this.setState({
      room: room,
      localMediaAvailable: true,
      hasJoinedRoom: true
    });

    Video.createLocalVideoTrack().then(track => {
      const localMedia = this.localMediaRef.current;
      localMedia.appendChild(track.attach());
      localMedia.querySelector("div.label").innerHTML = room.localParticipant.identity;
    });

    console.log(`Joined as ${this.state.identity}`);

    room.on('participantConnected', participant => {
      console.log(`Participant ${participant.identity} has joined the room.`);
      this.setState({ remoteMediaAvailable: true });
      participant.tracks.forEach(publication => {
        if (publication.isSubscribed) {
          this.trackSubscribed(publication.track);
        }
      });
      participant.on('trackSubscribed', track => {
        this.trackSubscribed(track);
      });
    });

    room.on('participantDisconnected', participant => {
      console.log(`Participant ${participant.identity} has left the room.`);
      this.setState({ hasJoinedRoom: false, localMediaAvailable: false, remoteMediaAvailable: false, remoteTracks: [] });
      const remoteMedia = this.remoteMediaRef.current;
      remoteMedia.innerHTML = ''; // Clear the container when a participant leaves

      console.log("---------participantDisconnected", participant)
    });
    

    room.participants.forEach(participant => {
      console.log(`Participant ${participant.identity} is connected to the room.`);
      this.setState({ remoteMediaAvailable: true });
      participant.tracks.forEach(publication => {
        if (publication.isSubscribed) {
          this.trackSubscribed(publication.track);
        }
      });
      participant.on('trackSubscribed', track => {
        // this.trackSubscribed(track);

        const remoteMedia = this.remoteMediaRef.current;
        remoteMedia.appendChild(track.attach());
        remoteMedia.querySelector("div.label").innerHTML = this.getRemoteLabel(room);
      });
    });

    room.on('disconnected', () => {
      console.log(`Disconnected from Room ${room.name}`);
      this.setState({ hasJoinedRoom: false, localMediaAvailable: false, remoteMediaAvailable: false, remoteTracks: [] });
      
      //room.localParticipant.stop()
      console.log("---------participantDisconnected", room.localParticipant)

      // Detach the local media elements
      //room.localParticipant.tracks.forEach(publication => {
      //  const attachedElements = publication.track.detach();
      //  attachedElements.forEach(element => element.remove());
      //});


      room.localParticipant.tracks.forEach(function(track) {
//        track.stop();
//        track.detach();
      });

      //localTrack.mediaStreamTrack.stop()


      room.localParticipant.tracks.forEach((track) => {
        console.log("---track", track.track)

        room.localParticipant.unpublishTrack(track.track);
        track.track.stop();
      });


/*
      room.localParticipant.tracks.forEach(publication => {
          publication.track.stop();

          const attachedElements = publication.track.detach();
          console.log("unsubscribed from: " + publication.track)
          attachedElements.forEach(element => element.remove());
      });
*/

      room.localParticipant.tracks.forEach(track => {
        console.log("xxxxxx track", track)
        //track.track.stop();
        //track.mediaStreamTrack.stop()
      })

      room.localParticipant.videoTracks.forEach(video => {
        console.log("xxxxxx video", video)



        //const trackConst = [video][0].track;
        //trackConst.stop();

        //trackConst.detach().forEach(element => element.remove());

        //room.localParticipant.unpublishTrack(trackConst);

      });
      


    //room.participants.forEach(participantDisconnected);
//    room.localParticipant.tracks.forEach((publication: Video.LocalTrackPublication) => {
//      console.log("---------publication", publication)

 //     publication.unpublish();
      //if (publication.track.kind !== 'data') trackUnsubscribed(publication.track);
 //   });

    });
  }

  getRemoteLabel(room) {
    let identity = "";
    for (let [key] of room.participants) {
      identity = room.participants.get(key).identity;
    }
    return identity;
  }

  trackSubscribed(track) {
    // Check if an HTML element for this track and participant already exists
    const existingMediaElement = document.getElementById(`${track.kind}-${track.sid}`);
    if (existingMediaElement) {
      existingMediaElement.appendChild(track.attach());
    } else {
      // Create a new HTML element for the new media track
      const mediaElement = document.createElement('div');
      mediaElement.id = `${track.kind}-${track.sid}`;
      mediaElement.appendChild(track.attach());
  
      // Append the new element to the remote-media-div
      const remoteMedia = this.remoteMediaRef.current;
      remoteMedia.appendChild(mediaElement);
      remoteMedia.querySelector("div.label").innerHTML = this.getRemoteLabel(this.state.room);
  
      // Add the new track to the remoteTracks array in the state
      this.setState({
        remoteTracks: [...this.state.remoteTracks, track]
      });
    }
  }
  

  leaveRoom() {
    const userId = getUserDetails().id;
    const url = `http://localhost:9000/api/twilio/room?userId=${userId}`;
  
    fetch(url, {
      method: 'PATCH',
      headers: {
        'Authorization': `Bearer ${getToken()}`
      }
    })
    .then(res => res.json())
    .then(() => {
      this.state.room.disconnect();
      this.setState({
        hasJoinedRoom: false,
        localMediaAvailable: false,
        remoteMediaAvailable: false,
        remoteTracks: []
      });
    });
  }
  

  render() {
    return (
      <div>

        {/*
        <TextField id="username" label="Username" value={this.state.username} onChange={this.handleUsernameChange}/>
        <TextField id="roomId" label="roomId" value={this.state.roomId} onChange={this.handleRoomChange}/>
        */}

        <Button
          variant={"contained"}
          color={"primary"}
          onClick={() => this.startComponent()}>
            Join Room
        </Button>

        {this.state.hasJoinedRoom ? (
          <div>
            <Button 
              variant={"contained"}
              color={"primary"}
              onClick={this.leaveRoom}>
                Leave Room
            </Button>

            <div className="feed feed1" id="remote-media-div" ref={this.remoteMediaRef}><div className="label"></div></div>

            {this.state.localMediaAvailable ? (
              <div className="feed feed2" id="local-media-div" ref={this.localMediaRef}><div className="label"></div></div>
            ) : (
              <p>Local media not available.</p>
            )}
          
          </div>
        ) : (
          <p>Joining room...</p>
        )}
      </div>
    );
  }
}
export default VideoChat;
The Old County
  • 89
  • 13
  • 59
  • 129

0 Answers0