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 MediaStream remote close by using an aux RTCDataChannel #963

Merged
merged 3 commits into from
Jun 22, 2023

Conversation

matallui
Copy link
Contributor

@matallui matallui commented May 25, 2022

Problem

MediaConnection.close() doesn't propagate the close event to the remote peer.

Solution

The proposed solution uses a similar approach to the DataConnection, where an aux data channel is created for the connection.
This way, when we MediaConnection.close() the data channel will be closed and the close signal will be propagated to the remote peer.

Notes

I was not sure if there was another cleaner way of achieving this, without the extra data channel, but this seems to work pretty well (at least until a better solution comes up).

This should fix: #636

@jonasgloning
Copy link
Member

Sorry for getting to this so late.
Thanks for the PR, LGTM! It’s on npm with the rc tag now!

@matallui
Copy link
Contributor Author

matallui commented Jun 8, 2022

@jonasgloning Thanks! Just did some quick testing with the rc build and it still seems to work fine.
Hopefully more people will get to confirm the results.

@markgeejw
Copy link

Hi, I can confirm that 1.4.6-rc.2 build works for me too. Thanks for the work!

@LarsFlieger
Copy link

When is this going live?

@asurovenko-zeta
Copy link

@matallui hello, can I help you somehow to go this to production? really need this fix

@matallui
Copy link
Contributor Author

matallui commented Apr 1, 2023

@asurovenko-zeta Release 1.4.8-rc1 seems to include a fix for this. I haven't really tested it, but give it a try. If that works I think we can drop this PR.

@neilyoung
Copy link

Problem

MediaConnection.close() doesn't propagate the close event to the remote peer.

Solution

The proposed solution uses a similar approach to the DataConnection, where an aux data channel is created for the connection. This way, when we MediaConnection.close() the data channel will be closed and the close signal will be propagated to the remote peer.

Notes

I was not sure if there was another cleaner way of achieving this, without the extra data channel, but this seems to work pretty well (at least until a better solution comes up).

This should fix: #636

I can confirm this to work, but it is not the proper way to solve this IMHO.

It does not merge into current master w/o conflicts, but I merged it manually. As said, it works, but it is a hack.

IMHO the proper solution would be to send a new OFFER on publisher's close, not containing the video channel and accepting the answer. This then should lead to a close event on subscriber side.

Anyway it works. But that this bug is open since so long is quite embarrassing for the maintainer(s) and not a good sign of reliability.

@matallui
Copy link
Contributor Author

matallui commented May 2, 2023

@neilyoung take a look at release 1.4.8-rc.1. They seem to have added a fix for this (different than the changes from this PR). Like I said, I opened this PR because I needed a fix and this was the way I got it working, but I assumed there would be better fixes.

If the fixes from RC don't work, you can always open a PR if you have some thoughts on how to fix this.

@neilyoung
Copy link

neilyoung commented May 2, 2023

Hmm. Thanks. At least from the release notes it looks like so. But I can't checkout that tag, somehow. Any hint?

Disregard please. Typo in version

@neilyoung
Copy link

Yes it works. And they have adopted your solution.

It remains a hack (no offence)

@matallui
Copy link
Contributor Author

matallui commented May 2, 2023

@neilyoung they have? I thought they did something much simpler ec1d5ae

Am I missing something?

@neilyoung
Copy link

Hmm. Now I'm not sure anymore. Let me checkout master again and then the RC. I had applied your patch manually... I stashed it and checked out the RC... Later checked the sources and found your changes...

@neilyoung
Copy link

That parcel build is strange. Look at this. Error in run 1, ok in run 2:

~/Documents/test/peerjs $ npm run build

> peerjs@1.4.8-rc.1 build
> rm -rf dist && parcel build


@parcel/transformer-typescript-types: Property 'byteLength' does not exist on type 'Blob'.

  /Users/decades/Documents/test/peerjs/lib/dataconnection.ts:262:25
    261 | 
  > 262 |       if (!chunked && blob.byteLength > util.chunkedMTU) {
  >     |                            ^^^^^^^^^^^ Property 'byteLength' does not exist on type 'Blob'.
    263 |         this._sendChunks(blob);
    264 |         return;


@parcel/transformer-typescript-types: Argument of type 'Blob' is not assignable to parameter of type 'ArrayBuffer'.

  /Users/decades/Documents/test/peerjs/lib/dataconnection.ts:263:22
    262 |       if (!chunked && blob.byteLength > util.chunkedMTU) {
  > 263 |         this._sendChunks(blob);
  >     |                          ^^^^^ Argument of type 'Blob' is not assignable to parameter of type 'ArrayBuffer'.
    264 |         return;
    265 |       }

✨ Built in 2.00s

dist/types.d.ts        10.72 KB     12ms
dist/bundler.cjs      112.43 KB     44ms
dist/bundler.mjs       122.3 KB     41ms
dist/peerjs.min.js    115.04 KB    622ms
dist/peerjs.js        273.74 KB     57ms
~/Documents/test/peerjs $ npm run build

> peerjs@1.4.8-rc.1 build
> rm -rf dist && parcel build

✨ Built in 129ms

dist/types.d.ts        10.72 KB     12ms
dist/bundler.cjs      112.43 KB     44ms
dist/bundler.mjs       122.3 KB     41ms
dist/peerjs.min.js    115.04 KB    622ms
dist/peerjs.js        273.74 KB     57ms
~/Documents/test/peerjs $ npm run build

@neilyoung
Copy link

Hasn't this been one of your changes? To negoiator.ts? It is in now.

		if (options.originator) {
			if (this.connection.type === ConnectionType.Data) {
				const dataConnection = <DataConnection>(<unknown>this.connection);

				const config: RTCDataChannelInit = { ordered: !!options.reliable };

				const dataChannel = peerConnection.createDataChannel(
					dataConnection.label,
					config,
				);
				dataConnection.initialize(dataChannel);
			} else if (this.connection.type === ConnectionType.Media) {
				const mediaConnection = <MediaConnection>(<unknown>this.connection);
				const dataChannel = peerConnection.createDataChannel(
					mediaConnection.connectionId,
				);
				mediaConnection.initialize(dataChannel);
			}

			this._makeOffer();
		} else {
			this.handleSDP("OFFER", options.sdp);
		}
	}

@matallui
Copy link
Contributor Author

matallui commented May 2, 2023

oh, maybe they just made changes on top of my changes... did't realize that. I agree, I don't think this is the solution, I just didn't know any better. If you have an idea on how to fix this in a better way, go for it. It'll be much appreciated.

@neilyoung
Copy link

I'm not sure if it is worth the efforts. This project seems to be pretty dead. And it doesn't support iterative addition/removal of streams, like lets start with data, then audio and later video and lets switch happily all these things on and off (like mediasoup). I tend to write my own client.

@neilyoung
Copy link

BTW: You did fine. You solved the problem. That's ok.

@jonasgloning jonasgloning merged commit e3b67a6 into peers:master Jun 22, 2023
@github-actions
Copy link

🎉 This PR is included in version 1.5.0-rc.1 🎉

The release is available on:

Your semantic-release bot 📦🚀

@matallui matallui deleted the fix_media_close branch August 14, 2023 15:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

call.on("close") not triggered
6 participants