jitsi / lib-jitsi-meet

A low-level JS video API that allows adding a completely custom video experience to web apps.
Apache License 2.0
1.34k stars 1.11k forks source link

Screen share loop issue #1124

Open Pinank opened 4 years ago

Pinank commented 4 years ago

I am using screen sharing using following configurations :

initOptions = {
    useIPv6: true,
    desktopSharingChromeExtId: "mbocklcggfhnbahlnepmldehdhpjfcjp",
    desktopSharingChromeDisabled: false,
    desktopSharingChromeSources: ["screen", "window", "tab"],
    desktopSharingChromeMinExtVersion: "0.1",
    desktopSharingFirefoxDisabled: false,
    disableAudioLevels: false,
    disableSimulcast: false,
    enableWindowOnErrorHandler: true,
    disableThirdPartyRequests: false,
    enableAnalyticsLogging: true
  };

Following function gets called on screen share :

screenShare() {
    let trackType = this.isVideo ? LocalTracksEnum.VIDEO : LocalTracksEnum.DESKTOP;
    if (this.localTracks[trackType]) {
      // this.localTracks[trackType].dispose();
      delete this.localTracks[trackType];
    }
    this.isVideo = !this.isVideo;
    trackType = this.isVideo ? LocalTracksEnum.VIDEO : LocalTracksEnum.DESKTOP;
    JitsiMeetJS.createLocalTracks({
      devices: [trackType]
    }).then(tracks => {
      this.localTracks[trackType] = tracks[0];
      this.localTracks[trackType].addEventListener(JitsiMeetJS.events.track.TRACK_MUTE_CHANGED, resp => {
        console.log("TRACK_MUTE_CHANGED : ", resp);
      });
      this.localTracks[trackType].addEventListener(JitsiMeetJS.events.track.LOCAL_TRACK_STOPPED, resp => {
        console.log("LOCAL_TRACK_STOPPED : ", resp);
        this.screenShare();
      });
      const ele = document.getElementById("local_video");
      this.localTracks[trackType].attach(ele);
      this.room.addTrack(this.localTracks[trackType]);
    }).catch(error => {
      console.error(error);
    });
  }

Whenever i try to share screen, window goes into loop. Also screen is not shared at other end. I am attaching screensort

Screenshot 2020-04-27 at 11 25 48 PM

If anyone had faced the issue than please help to get out!

hristoterezov commented 4 years ago

This is not related to any options and constraints! When you screen share the display which actually displays the Screen sharing content, you get a screen share loop. This is basically the same as the scenario where you put a mirror in front of the mirror. You will see the same result.

About the other part of the problem. Try to first remove the existing video track from the conference and then add the screen sharing track (you are already adding it). If you do this, there's a big chance to fix the problem.

Pinank commented 4 years ago

@hristoterezov Thanks for the quick response.

This is not related to any options and constraints! When you screen share the display which actually displays the Screen sharing content, you get a screen share loop. This is basically the same as the scenario where you put a mirror in front of the mirror. You will see the same result.

Ok. Just one more doubt than. Why it's working fine in case of Skype and other medias. If we stay on the same screen than also it shows only once.

About the other part of the problem. Try to first remove the existing video track from the conference and then add the screen sharing track (you are already adding it). If you do this, there's a big chance to fix the problem.

As you said i am already doing this in screenshare method. Still its not working and also not showing screen to other members

akuckartz commented 4 years ago

This is basically the same as the scenario where you put a mirror in front of the mirror.

Maybe it is possible to build an "intelligent" mirror with a different behaviour?

ashitikov commented 4 years ago

@hristoterezov Thanks for the quick response.

This is not related to any options and constraints! When you screen share the display which actually displays the Screen sharing content, you get a screen share loop. This is basically the same as the scenario where you put a mirror in front of the mirror. You will see the same result.

Ok. Just one more doubt than. Why it's working fine in case of Skype and other medias. If we stay on the same screen than also it shows only once.

About the other part of the problem. Try to first remove the existing video track from the conference and then add the screen sharing track (you are already adding it). If you do this, there's a big chance to fix the problem.

As you said i am already doing this in screenshare method. Still its not working and also not showing screen to other members

  1. Actually, I see that you've commented // this.localTracks[trackType].dispose();. If this is intended behavior and you already tried to dispose video track see the next option.
  2. You built a dispose-create behavior based on trackType, which depends on this.isVideo. Make sure that you disposed ANY video track, it means that if you previously create local track with either desktop or video types you should dispose it before you are trying to add new desktop track to the conference.
  3. track.dispose() is an async function, so you have to make sure, that this.room.addTrack(this.localTracks[trackType]); happens after and only after the result of dispose.
  4. If you are switching between video track and desktop track I recommend to use replaceTrack(video, desktop) method instead, although in my project I use dispose for switching between tracks anyway.

If you double-checked steps that I described and anyway nothing works, please, provide verbose logs of moment, when you are trying to enable screensharing.

saghul commented 4 years ago

Maybe it is possible to build an "intelligent" mirror with a different behaviour?

This funccttionality is provided by the browser, you'd have to ask them.

Pinank commented 4 years ago

@hristoterezov Thanks for the quick response. This is not related to any options and constraints! When you screen share the display which actually displays the Screen sharing content, you get a screen share loop. This is basically the same as the scenario where you put a mirror in front of the mirror. You will see the same result. Ok. Just one more doubt than. Why it's working fine in case of Skype and other medias. If we stay on the same screen than also it shows only once. About the other part of the problem. Try to first remove the existing video track from the conference and then add the screen sharing track (you are already adding it). If you do this, there's a big chance to fix the problem. As you said i am already doing this in screenshare method. Still its not working and also not showing screen to other members

  1. Actually, I see that you've commented // this.localTracks[trackType].dispose();. If this is intended behavior and you already tried to dispose video track see the next option.
  2. You built a dispose-create behavior based on trackType, which depends on this.isVideo. Make sure that you disposed ANY video track, it means that if you previously create local track with either desktop or video types you should dispose it before you are trying to add new desktop track to the conference.
  3. track.dispose() is an async function, so you have to make sure, that this.room.addTrack(this.localTracks[trackType]); happens after and only after the result of dispose.
  4. If you are switching between video track and desktop track I recommend to use replaceTrack(video, desktop) method instead, although in my project I use dispose for switching between tracks anyway.

If you double-checked steps that I described and anyway nothing works, please, provide verbose logs of moment, when you are trying to enable screensharing.

I updated code to this,

 screenShare() {
    let newTrackType = this.isVideo ? TrackEnum.DESKTOP : TrackEnum.VIDEO;
    JitsiMeetJS.createLocalTracks({
      devices: [newTrackType]
    }).then(tracks => {
      let currentTrackType = this.isVideo ? TrackEnum.VIDEO : TrackEnum.DESKTOP;
      if (this.localTracks[currentTrackType]) {
        this.room.removeTrack(this.localTracks[currentTrackType]);
        this.localTracks[currentTrackType].dispose();
        delete this.localTracks[currentTrackType];
      }
      this.isVideo = !this.isVideo;
      this.localTracks[newTrackType] = tracks[0];
      this.localTracks[newTrackType].addEventListener(JitsiMeetJS.events.track.TRACK_MUTE_CHANGED, resp => {
        console.log("TRACK_MUTE_CHANGED : ", resp);
      });
      this.localTracks[newTrackType].addEventListener(JitsiMeetJS.events.track.LOCAL_TRACK_STOPPED, resp => {
        console.log("LOCAL_TRACK_STOPPED : ", resp);
        this.screenShare();
      });
      const ele = document.getElementById("local_video");
      this.localTracks[newTrackType].attach(ele);
      this.room.addTrack(this.localTracks[newTrackType]);
    }).catch(error => {
      console.error(error);
    });
  }

Result is same Screenshot 2020-04-29 at 12 28 56 PM

Also now it has started giving new error in console.

Screenshot 2020-04-29 at 12 29 33 PM

It is giving error on this.room.addTrack(this.localTracks[newTrackType]); code

ashitikov commented 4 years ago

This states that you are trying to add desktop track, while video track is still in conference. I do not quite understand what you are trying to achieve by compute newTrackType and currentTrackType in the same way.

Try to use this.localTracks[TrackEnum.VIDEO].dispose();

Pinank commented 4 years ago

This states that you are trying to add desktop track, while video track is still in conference. I do not quite understand what you are trying to achieve by compute newTrackType and currentTrackType in the same way.

Try to use this.localTracks[TrackEnum.VIDEO].dispose();

It would be same brother. Initially video is on so this.isVideo will be true. Now try to evaluate the operation your self,

this.localTracks[TrackEnum.VIDEO].dispose(); i am already doing this, i this block,

if (this.localTracks[currentTrackType]) {
        this.room.removeTrack(this.localTracks[currentTrackType]);
        this.localTracks[currentTrackType].dispose();
        delete this.localTracks[currentTrackType];
      }

i am also posting the code,

screenShare() {
    // let newTrackType = this.isVideo ? TrackEnum.DESKTOP : TrackEnum.VIDEO;
    let newTrackType = TrackEnum.DESKTOP;
    JitsiMeetJS.createLocalTracks({
      devices: [newTrackType]
    }).then(tracks => {
      // let currentTrackType = this.isVideo ? TrackEnum.VIDEO : TrackEnum.DESKTOP;
      let currentTrackType = TrackEnum.VIDEO;
      if (this.localTracks[currentTrackType]) {
        this.room.removeTrack(this.localTracks[currentTrackType]);
        this.localTracks[currentTrackType].dispose();
        delete this.localTracks[currentTrackType];
      }
      this.isVideo = !this.isVideo;
      this.localTracks[newTrackType] = tracks[0];
      this.localTracks[newTrackType].addEventListener(JitsiMeetJS.events.track.TRACK_MUTE_CHANGED, resp => {
        console.log("TRACK_MUTE_CHANGED : ", resp);
      });
      this.localTracks[newTrackType].addEventListener(JitsiMeetJS.events.track.LOCAL_TRACK_STOPPED, resp => {
        console.log("LOCAL_TRACK_STOPPED : ", resp);
        this.screenShare();
      });
      const ele = document.getElementById("local_video");
      this.localTracks[newTrackType].attach(ele);
      this.room.addTrack(this.localTracks[newTrackType]);
    }).catch(error => {
      console.error(error);
    });
  }

Out put is same

Screenshot 2020-04-29 at 1 36 40 PM

I notice one more behaviour while removing track from room. I am removing single video track from room and in room's TRACK_REMOVED listener method i am getting two callbacks. first is audio and second is video. This is strange

this.room.on(JitsiMeetJS.events.conference.TRACK_REMOVED, track => {
      console.log(
        `track removed!!!${track}`
      );
    });

Screenshot 2020-04-29 at 1 35 41 PM

ashitikov commented 4 years ago

this.room.removeTrack(this.localTracks[currentTrackType]); this.localTracks[currentTrackType].dispose();

Screen share loop is okay. With this code if you get the same behavior on addTrack() you should probably do addTrack() only after this.localTracks[currentTrackType].dispose(); will be done. So you either wrap your addTrack() to this.localTracks[currentTrackType].dispose().then(() => {}) closure either use async/await pattern.

Pinank commented 4 years ago

this.room.removeTrack(this.localTracks[currentTrackType]); this.localTracks[currentTrackType].dispose();

Screen share loop is okay. With this code if you get the same behavior on addTrack() you should probably do addTrack() only after this.localTracks[currentTrackType].dispose(); will be done. So you either wrap your addTrack() to this.localTracks[currentTrackType].dispose().then(() => {}) closure either use async/await pattern.

With async/await worked. Thanks Now loop issue and listener calling twice. Still figuring this out

this.room.on(JitsiMeetJS.events.conference.TRACK_REMOVED, track => {
      console.log(
        `track removed!!!${track}`
      );
    });
ashitikov commented 4 years ago

Loop issue is not an issue, @hristoterezov already explained you why this happens:

This is not related to any options and constraints! When you screen share the display which actually displays the Screen sharing content, you get a screen share loop. This is basically the same as the scenario where you put a mirror in front of the mirror. You will see the same result.

What about TRACK_REMOVED: I can't help you here because you didn't provide any code how do you manage audio tracks. I think you need to double check your code and make sure that you do not dispose audio track. Also this could happen in case of switching p2p to jvb and vice-versa.

Pinank commented 4 years ago

Loop issue is not an issue, @hristoterezov already explained you why this happens:

This is not related to any options and constraints! When you screen share the display which actually displays the Screen sharing content, you get a screen share loop. This is basically the same as the scenario where you put a mirror in front of the mirror. You will see the same result.

What about TRACK_REMOVED: I can't help you here because you didn't provide any code how do you manage audio tracks. I think you need to double check your code and make sure that you do not dispose audio track. Also this could happen in case of switching p2p to jvb and vice-versa.

TRACK_REMOVED issue is resolved with async/await.

Can we have a call over jitsi so i can showcase everything i have done?

codingground commented 4 years ago

Hi Pinank, I was following your discussion on this and looking forward to see how exactly you resolved your profile using async/await.

I'm facing various other problem with addTrack, removeTrack which I can resolve using async/await. So if you don't have any constraints then can you please share your piece of code here showing the usage of async/await.

Thank you very much in advance.

Pinank commented 4 years ago

@codingground async/await is for track dispose only as it returns promise. AddTrack & Remove Track does not require promise.