-
Notifications
You must be signed in to change notification settings - Fork 22
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
New WebRTC #151
New WebRTC #151
Conversation
joaoantoniocardoso
commented
Dec 22, 2022
•
edited
Loading
edited
src/composables/webRTC.ts
Outdated
|
||
// Regularly asks for available streams, which will trigger the consumer "on_available_streams" callback | ||
let handler_id: number | undefined = undefined | ||
handler_id = window.setInterval(() => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Will this interval be ended if the component is removed?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
great one, interval's life is independent, right? So it will never be collected if we don't clear it... Any suggestion on how to do it properly?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
actually, probably this setInterval will prevent its parent object (this
) from being collected, right? 🤦
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Similarly, maybe all those callbacks (e.g. on_track_added
in Session
) might need to be set to undefined
too for the Session
to be collected..? ..Or are they something like weak references and they don't count for the garbage collection thing? @patrickelectric
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If I remember correctly, the parent will be collected, but the interval will keep running (the former I'm sure).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
After some research and reasoning, my understanding is the following:
this
will only be collectible if this arrow function is collectible.- the interval arrow function will only be collectible if
id
is nullified. id
is not being nullified, even whenthis
ends
To this point, id
is never nullified, thus, neither the interval arrow function nor this
will be ever collected.
To enable the interval arrow function to be collectible, we might need to:
- set
id = undefined
after everyclearInterval(id)
- create another condition to make sure that:
- if
this
ends, the interval will be cleared and theid
will be nullified.
- if
The only ways I see to make it possible is to:
- make the
id
a private property ofthis
and nullify it inside itsend()
method. - create a private boolean property, like
ended
, set to false in itsend()
, and use it inside the arrow function to nullify the id and clear the interval, which seems better
src/libs/webrtc/session.ts
Outdated
*/ | ||
private onTrackAdded(event: RTCTrackEvent): void { | ||
let id: number | undefined = undefined | ||
id = window.setInterval(() => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Will this interval be ended if the component is removed?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's not a full review, it's just a tribute.
src/composables/webRTC.ts
Outdated
const addAvailablePeer = (peerId: string, displayName: string): void => { | ||
removeAvailablePeer(peerId) | ||
availablePeers.value.push({ id: peerId, displayName }) | ||
const consumer_id: Ref<string | undefined> = ref() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We avoid snake_case when possible.
src/composables/webRTC.ts
Outdated
const rtc_configuration: RTCConfiguration = { iceServers: [] } | ||
const status: Ref<string> = ref('waiting...') | ||
|
||
const updateStatus = (new_status: string): void => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We avoid snake_case when possible.
src/composables/webRTC.ts
Outdated
|
||
const updateStatus = (new_status: string): void => { | ||
status.value = new_status | ||
console.log(`Status updated: ${new_status}`) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You probably want to add a prefix for the message like webRTC:
or something.
That would be more a console.debug
than console.log
src/composables/webRTC.ts
Outdated
clearInterval(handler_id) | ||
} | ||
|
||
signaller.requestStreams() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why this need to be inside the timer inside of a websocket connection ?
Can't we put it totally outside ? That should fix the clearInterval
issue.
}, | ||
{ once: true } | ||
) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Making this a singleton component that will be accessible by video widgets would fix the unmount logic
src/composables/webRTC.ts
Outdated
console.warn(`Socket for session '${sessionId.value}' already undefined.`) | ||
return | ||
const startSession = (producer_id: string): void => { | ||
{ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we check consumer_id
before the playing message ?
src/composables/webRTC.ts
Outdated
if (sessionWebSocket.value === undefined) { | ||
resetSocket() | ||
const stream = available_streams.value.find((s) => s.id === producer_id) | ||
console.debug(`stream: ${stream}`) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This debug message should be after the if check, the if check message will already provide the necessary information if the value is undefined.
@rafaellehmkuhl @patrickelectric there are two (similar) cases where it's not behaving as expected:
|
} | ||
|
||
if (selectedStream.value === undefined) { | ||
console.debug!('[WebRTC] trying to set stream...') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does it make sense to not return if the selectedStream
is undefined ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, regardless of selectedStream
being undefined, when we get a defined savedStream
different from selectedStream
, we want selectedStream
to receive the value of the found savedStream
.
This should be enough to guarantee that the saved stream is synched with the available streams and that the selected stream is only be updated to a valid stream. We could, however, want the selectedStream
to go back to 'undefined' when we don't find the saved stream in the list of available streams. This change would make the combobox be shown as empty when the saved stream is not available.
src/composables/webRTC.ts
Outdated
if (oldStream !== undefined) { | ||
this.stopSession(msg) | ||
} | ||
if (newStream !== undefined && newStream !== oldStream) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if (newStream !== undefined && newStream !== oldStream) { | |
if (newStream !== undefined) { |
The first if of the logic takes care of it
src/composables/webRTC.ts
Outdated
* @param {RTCTrackEvent} event | ||
* @returns {boolean} | ||
*/ | ||
private onTrackAdded(event: RTCTrackEvent): boolean { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does it make sense to return a value at all ? If its always true
this.signaller.requestSessionId( | ||
this.consumerId, | ||
producerId, | ||
(receivedSessionId: string): void => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
isn't better to break it on own its function over a huge lambda ?
src/libs/webrtc/session.ts
Outdated
* Defines the behavior for the RTCPeerConnection's 'onconnectionstatechange' event | ||
*/ | ||
private onConnectionStateChange(): void { | ||
switch (this.peerConnection.connectionState) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You should save the state as a variable inside this function to be used for msgs when necessary, avoiding the long property path
src/libs/webrtc/session.ts
Outdated
const msg = `RTCPeerConnection state changed to ${this.peerConnection.connectionState}` | ||
console.debug('[WebRTC] [Session] ' + msg) | ||
|
||
if (this.peerConnection.connectionState == 'failed') { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should never happen since state will be disconnected
src/libs/webrtc/session.ts
Outdated
// Cleanup event listeners | ||
this.peerConnection.removeEventListener('track', this.onTrackAddedCallback.bind(this)) | ||
this.peerConnection.removeEventListener('icecandidate', this.onIceCandidate.bind(this)) | ||
this.peerConnection.removeEventListener('iceconnectionstatechange', this.onIceConnectionStateChange.bind(this)) | ||
this.peerConnection.removeEventListener('connectionstatechange', this.onConnectionStateChange.bind(this)) | ||
this.peerConnection.removeEventListener('signalingstatechange', this.onSignalingStateChange.bind(this)) | ||
this.peerConnection.removeEventListener('icegatheringstatechange', this.onIceGatheringStateChange.bind(this)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You should encapsulate this logic under a function and use it in end
and reconnected
Use the reset video settings on BlueOS
…On Tue, Jan 31, 2023, 12:00 João Antônio Cardoso ***@***.***> wrote:
Joao, I'm not able to list streams. Is this because I don't have streams
available? Should I create an UDP stream so a webRTC one is created?
[image: image]
<https://user-images.githubusercontent.com/6551040/215792152-55d361bd-0922-4b10-b6d1-efe0ea68109c.png>
PS: I have created the following stream and yet I don't have webRTC
streams available.
[image: image]
<https://user-images.githubusercontent.com/6551040/215792637-129cd9ac-8b39-488e-b494-5ce3a8ff0b63.png>
Yes, you need to create a stream, but it needs to be an H264 encoded one
—
Reply to this email directly, view it on GitHub
<#151 (comment)>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/AAJIYCISXLO7AJPKYKQILS3WVESKHANCNFSM6AAAAAATGZCDIQ>
.
You are receiving this because you were mentioned.Message ID:
***@***.***>
|
Is the thumbnail normal ? I'm having the same problem on BlueOS when using my mac |
No. H264 + UDP gives me no thumbnail and blank stream. |
Also new to me. Apparently if the source has no audio, we can autoplay. So just add a |
Strange, there is one already. You shouldn't be receiving this warn... |
Apparently this changes from browser to browser. |
Yeah, I didn't get why Firefox is complaining, maybe there's a hidden related to WebRTC. We can check if it can autoplay, and create a popup asking the user to click a button that will call the play. Probably in another PR hehe |
After some investigation, the (1) is on the signalling server side, and (2) was finally solved here :) |
export type Message = | ||
| { | ||
/** | ||
* |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This empty comments are a sad thing to see
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, one day, maybe..: Aleph-Alpha/ts-rs#52
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can add the necessary permission request later
src/assets/defaults.ts
Outdated
bundlePolicy: 'max-bundle', | ||
iceServers: [ | ||
{ | ||
urls: `turn:blueos.local:3478`, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should use the same address as the network configuration of cockpit
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Or at least allow configuring it somehow
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should not have addresses in default.ts
, the mavlink one should also be contemplated by the solution. Do you think this should be handled in this PR?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OH, it already has a configuration. I'll do that for these :D
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So just to be sure, you will take the same address from the mainVehicle
store and parse it, right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Perfect. Was going to suggest that haha
fixes #209 |
Well, it's merged, but we still need to make those custom ips/addresses permanent (saved in the store) and reactive. @rafaellehmkuhl is helping me with it |
Yes, I saw that, but merged to get a release since this fixes should not hold the test release. |