Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix replacestream #12

Merged
merged 3 commits into from
Oct 12, 2017
Merged

Fix replacestream #12

merged 3 commits into from
Oct 12, 2017

Conversation

y-i
Copy link
Contributor

@y-i y-i commented Sep 25, 2017

In Firefox, even if a client who is only sending audio uses replaceStream to add video, the client can not send video. This PR fixes it.
Multi track will be implemented after Chrome uses Unified Plan SDP.

Copy link
Contributor

@iwashi iwashi left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As I commented, can you confirm these case?

  • both video and audio -> only audio
  • audio -> both video and audio
  • both video and audio -> both video and audio // As regression

@@ -114,6 +114,23 @@ class Negotiator extends EventEmitter {
}
});

if (this._pc.getSenders().every(sender => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

About L:117-130, what happens in the use case described below?

  1. The user has both an audio and a video track; which means, _pc.getSenders() should return the array including 2 rtpSender.
  2. Then user wants to stop sending the video track to reduce bandwidth, so s/he calls replaceStream(newStream) where newStream contains only the audio track.
  3. Does the user can successfully create an offer SDP and communicate with the other party after negotiation as the user expects?

@@ -114,6 +114,23 @@ class Negotiator extends EventEmitter {
}
});

if (this._pc.getSenders().every(sender => {
return sender.track.kind !== 'audio';
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Personally I prefer extracting this condition to another method like,

Before

      if (this._pc.getSenders().every(sender => {
        return sender.track.kind !== 'audio';
      }))

After

      if (_onlyVideoTracksExist(this._pc)) { ...}

This explains what we're doing in the condition.

@y-i y-i changed the base branch from v1.0.2 to release/1.0.2 September 27, 2017 06:49
@y-i y-i force-pushed the fix_replacestream branch 2 times, most recently from 0c12526 to 44b7f99 Compare September 28, 2017 05:37
@@ -407,6 +366,7 @@ class Negotiator extends EventEmitter {
return this._pc.setLocalDescription(answer)
.then(() => {
logger.log('Set localDescription: answer');
logger.log(`Setting local description ${JSON.stringify(answer.sdp)}`);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Even if user set log level to 0, JSON.stringify() is called.
Is it ok?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

JSON.stringify() is called at _setRemoteDescription too. So I think it is ok.

this._pc.addTrack(track, newStream);
} else {
// need to check id before replace..?
vSenders[idx].replaceTrack(track);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As I commented here, what will happen when trying to replace track A with track A?

this._pc.removeStream(localStreams[0]);
}

this._replaceStreamCalled = true;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This line should be placed after this._pc.addStream(newStream); for naming..?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

_replaceStreamCalled is true after replaceStream and is false after onnegotiationneeded.
_replaceStreamCalled is used to check if onnegotiationneeded event has finished or not.
If it is placed after addStream, _replaceStreamCalled becomes true after onnegotiationneeded.

@@ -477,6 +438,77 @@ class Negotiator extends EventEmitter {
}

/**
* Replace the stream being sent with a new one.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you add comments to differentiate _replacePerTrack() and _replacePerStream()?

@alanmshelly
Copy link
Contributor

alanmshelly commented Oct 4, 2017

NOTE: more discussion here: https://gist.github.com/leader22/fb538265d7f24217dada1d6b8a8d2380

it('should not call addTrack for audio sender', () => {
negotiator.replaceStream(newStream);

console.log(negotiator._pc.getSenders());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can you get rid of this?
I'm assuming it's for debugging

return;
}
// if track was not replaced, do nothing
if (sender.track.id === track.id) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The tests are failing

screen shot 2017-10-05 at 16 39 03

I'm not sure but I think this line might be the problem. Could you see what setting the track.id in the tests does?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In this test, both stubs of senders and stubs of tracks do not have id key. So I think this statement is always true because it is undefined === undefined.

@alanmshelly
Copy link
Contributor

The direction of the code looks good. Thanks! 👍

@alanmshelly
Copy link
Contributor

LGTM! 👍
Could you please rebase and clean up the commit log? (you can force push to this branch)

@iwashi
Copy link
Contributor

iwashi commented Oct 10, 2017

LGTM!
Could @y-i make a last check on browsers?

@y-i
Copy link
Contributor Author

y-i commented Oct 10, 2017

skyway.js:420 SkyWay:  DOMException: Failed to set local answer sdp: Called in wrong state: STATE_INPROGRESS
skyway.js:420 SkyWay:  DOMException: Failed to set local answer sdp: Called in wrong state: STATE_INPROGRESS
skyway.js:439 SkyWay:  signalingState is stable
index.html:1 Uncaught (in promise) DOMException: Failed to set local answer sdp: Called in wrong state: STATE_INPROGRESS

@y-i
Copy link
Contributor Author

y-i commented Oct 12, 2017

I checked on Chrome and Firefox.

…replaceStream

If `getSenders` is not defined, `addTrack` will not be defined either.
If broweser dosen't support `getSenders`, stream is replaced by stream. Otherwise stream is replaced per stream.
We assume that there are at most 1 audio and at most 1 video in local stream.
@alanmshelly
Copy link
Contributor

LGTM!

@iwashi
Copy link
Contributor

iwashi commented Oct 12, 2017

image

@iwashi iwashi merged commit 51045b3 into release/1.0.2 Oct 12, 2017
@iwashi iwashi deleted the fix_replacestream branch October 12, 2017 06:42
this._replaceStreamCalled = true;

// a chance to trigger (and do nothing) on removeStream.
setTimeout(() => {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add setTimeout before addStream to fix state error on chrome

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
4 participants