AgoraIO / rtc-web-archive

Other
22 stars 29 forks source link

Mute/unmute audio will unmute video #15

Open fakkio opened 4 years ago

fakkio commented 4 years ago

Hi,

when I mute/unmute audio on localStream, it will unmute video too. Why? How can I toggle audio without unmuting video?

(Same issue with enable/disable too)

Thanks, Fabio.

plutoless commented 4 years ago

could you pls provide your logs and code snippet? usually muting audio should not affect video

fakkio commented 4 years ago

Ok, hope I can help. Starting from Agora-Web-Tutorial-1to1-React example, I've simply added:

  const [isVideoMuted, setVideoMute] = useState(false);
  const [isAudioMuted, setAudioMute] = useState(false);

...

  const muteVideo = () => {
    if (isVideoMuted) {
      setVideoMute(false);
      console.log("Enable video");
      localStream.unmuteVideo();
    } else {
      setVideoMute(true);
      console.log("Disable video");
      localStream.muteVideo();
    }
  };

  const muteAudio = () => {
    if (isAudioMuted) {
      setAudioMute(false);
      console.log("Enable audio");
      localStream.unmuteAudio();
    } else {
      setAudioMute(true);
      console.log("Disable audio");
      localStream.muteAudio();
    }
  };

...

    <button onClick={muteVideo} disabled={!localStream}>muteVideo</button>
    <button onClick={muteAudio} disabled={!localStream}>muteAudio</button>

Then simply run the app and click on the buttons, first on muteVideo, and then on muteAudio. As you can see in the console log, video is muted (log line: 112-113), but when I click on muteAudio (log line: 114-115), video is unmuted (log line: 131)

localhost-1591609382606.log

plutoless commented 4 years ago

are you sure you are not calling localStream.enableVideo somewhere else? the console logs indicates you are calling this api somewhere in your code. could you pls set a breakpoint in our minified sdk and check the call stack?

fakkio commented 4 years ago

TLDR: I think the problem is in the agora-stream-player component, not in this one.

Here the stacktrace:

AgoraRTCSDK.min.js:8 debug
Ae.t.enableVideo @ AgoraRTCSDK.min.js:8
push../node_modules/agoran-awe/lib/promisify.js.exports.promisifyStream @ promisify.js:91
apply @ enhance.js:18
_this._handleStreamSideEffects @ index.js:103
componentDidUpdate @ index.js:129
commitLifeCycles @ react-dom.development.js:19835
commitLayoutEffects @ react-dom.development.js:22803
callCallback @ react-dom.development.js:188
invokeGuardedCallbackDev @ react-dom.development.js:237
invokeGuardedCallback @ react-dom.development.js:292
commitRootImpl @ react-dom.development.js:22541
unstable_runWithPriority @ scheduler.development.js:653
runWithPriority$1 @ react-dom.development.js:11039
commitRoot @ react-dom.development.js:22381
finishSyncRender @ react-dom.development.js:21807
performSyncWorkOnRoot @ react-dom.development.js:21793
(anonymous) @ react-dom.development.js:11089
unstable_runWithPriority @ scheduler.development.js:653
runWithPriority$1 @ react-dom.development.js:11039
flushSyncCallbackQueueImpl @ react-dom.development.js:11084
flushSyncCallbackQueue @ react-dom.development.js:11072
discreteUpdates$1 @ react-dom.development.js:21893
discreteUpdates @ react-dom.development.js:806
dispatchDiscreteEvent @ react-dom.development.js:4168
AgoraRTCSDK.min.js:2 17:45:09:302 Agora-SDK [WARNING]: [4125375363] Stream.enableVideo is deprecated and will be removed in the future. Use Stream.unmuteVideo instead

to be precise, the issue is here

_this._handleStreamSideEffects @ index.js:103

that is

100      // check video
101      if (xor($prev.videoOn, _this.props.video)) {
102        if ($stream.hasVideo()) {
103          _this.props.video ? $stream.enableVideo() : $stream.disableVideo();
104        }
105      }

of the agora-stream-player component.

samitabhishek commented 3 years ago

Hey @Fakkio Did you find any soulution for this . even i am getting this issue

fakkio commented 3 years ago

Hey @Fakkio Did you find any soulution for this . even i am getting this issue

@samitabhishek I used this worlaround:

  const muteAudio = () => {
    if (isAudioMuted) {
      setIsAudioMute(false);
      localStream?.unmuteAudio();
    } else {
      setIsAudioMute(true);
      localStream?.muteAudio();
    }

    // Since for a bug muting and unmuting the audio re-enables the video,
    // we need to deactivate the video in case it should be disabled
    if (isVideoMuted) {
      setTimeout(() => {
        localStream?.muteVideo();
      }, 10);
    }
  };

I Hope it could help

patelmilanun commented 3 years ago

Thanks @Fakkio for workaround. I had the same issue and now I'm using this workaround. Can u tell me why are you using setTimeout? Cuz it gives like a flash of video starting and stopping.

fakkio commented 3 years ago

Thanks @Fakkio for workaround. I had the same issue and now I'm using this workaround. Can u tell me why are you using setTimeout? Cuz it gives like a flash of video starting and stopping.

I don't remember exactly, I think I needed to wait the dom to update and then mute the video, otherwise it didn't work for some reason. I didn't have this flash issue though. You can try with a 1ms timeout or even with 0ms.

patelmilanun commented 3 years ago

TL;DR; Just add autoChange={false} when you are creating the <StreamPlayer>. Look at the example at the end.

Hehe BOI, I found an actual solution to this problem. So after I wrote above comment I downloaded the source code to see why the error is coming. I found that they are updating the state of audio and video inside componentDidUpdate(). Which is calling 2 function which checks for if state of previous audio is off than turn on it and if state of previous video is off than turn on it and vice versa.

Now the problem is coming when we are updating only video or audio. So if we update state of any one from audio or video. These 2 functions are called. Now that is a big problem of logic here.

Assume your condition here where initially video and audio both on. Now you update just video state from on to off. So far so good. Because after calling both the functions we are not changing anything except video's function.

Ok, so keeping video disabled now we are going to change audio from on to off. Here comes the problem. After calling both functions the function for audio triggers expected result as the previous state of audio was on. So it is gonna try to turn it off. But what we don't want is to call the function for video. Because if it runs than it change state of the video to on. As it is the function which simply set the value to negate value of the original one.

Here is the function which i was talking about and which is called inside componentDidUpdate()

handleStreamSideEffects = () => {

  if (!this.props.autoChange) {
    return;
  }

  // deal with side effect
  let $prev = this._snapshot;
  let $stream: Stream = (this.props.stream: any);

  // check video
  if (xor($prev.videoOn, this.props.video)) {
    if ($stream.hasVideo()) {
      this.props.video ? $stream.enableVideo() : $stream.disableVideo();
    }
  }

  // check audio
  if (xor($prev.audioOn, this.props.audio)) {
    if ($stream.hasAudio()) {
      this.props.audio ? $stream.enableAudio() : $stream.disableAudio();
    }
   }
}

Imagine this both functions inside this function called on every update. So that is our main problem. Now as you can see in the same function there is one flag checking. So if we somehow managed to set that flag we can bypass this whole function call.

So in order to so that i.e, change the value of this.props.autoChange you need to pass it as an option to <StreamPlayer>. Below is an example of doing so

<StreamPlayer stream={localStream} fit="contain" autoChange={false} />

As you can see I made autoChange to false. And bam the things now works as expected.

Gnanaprakash1999 commented 2 years ago

I have using flutter agora for live streaming app. When I use void _onToggleMute() { setState(() { muted = !muted; }); _engine.muteLocalAudioStream(muted); }

The above code... When I click mute button... It mute both audio and video streaming on the website...When I refresh the Webpage... Then the video stream was continued... I don't want to refresh the Webpage when I mute the audio...the video stream should be continue....

Pls respond as soon as possible...