-
Notifications
You must be signed in to change notification settings - Fork 105
Conversation
Also please add the tests like if you wanted them to run with the others, but leave it commented out and with a mark like this:
So when we make the jump the code can be easily found and the test enabled. |
Just done, also made a change to the ice_state_changes test due to race condition that may cause a segfault |
Sorry I've been playing with the "Review PR" feature of Github, last night I made several comments on parts of the code, but I think you didn't see them (did you before now? just to know) because I didn't click the button to "start a review" |
(cherry picked from commit d3ed7b78b32aaa099ec34d0f7b7afff98b485877)
Changes done!. Incidentally, getting internal elements by name was already being done in KmsWebRtcTransportSink to configure internal funnel and srtp encoder. So I also changed also that, thus they are ready for updating to GStreamer 1.18+ |
Nice, thanks. I said that about internal names, because I know for a fact that it is (or was) being done in some places of Kurento already, and we found about it during the initial stages of Kurento 7.0, porting to GStreamer 1.14, where some names had already changed. So better to search by type instead of name. Only issue would be when multiple elements of the same type are in the Bin, but for simple cases like this one (only 1 element of a given type) it's trivial and more robust. Hopefully we can upgrade soon to GStreamer 1.18. What version of Ubuntu comes (or will come) with it? |
I am afraid that GStreamer 1.18 is available on a non LTE version, hirsute I think |
@slabajo I've reviewed the newest changes. Did you test again with them? I'm not sure about something here, memory wise, and would like to review with you. Before the latest review, you used Checking the docs, I think the difference between So here I see that What do you think? |
@j1elo In fact I got exactly the same doubt, because it is not clear, at least from documentation, how are iterated objects transfered or not. In principle, logic seems to tell that semantic should be as similar as possible to the get_object_by_xxxxx, but as I say it is not clear from the docs. So I just tested it. Here you can see the reference count of one the inner elements in dtlssrtpenc bin (for instance the funnel element) before getting the iterator to the inner elements: You can see reference count is one. Then after the iterator moves to the selected element: As you can see ref count has been incremented when the iterator moves to that element, interestingly enough it is not incremented when the iterator is retrieved. It increments only when the iterator moves to the element. Also when you move the iterator to the next element, the previous one gets unreferenced Of course, as you say the g_value_get_object does not increment reference count, it remains to 2: Last, but not least, when iterator is released, reference count from retrieved objects is not decreased: So, it seems the algorithm is ok as the loop gets the elements reffed on each gst_iterator_next and dereffed when we execute next gst_iterator_next. and only gets reffed when we reached the one we are looking for, as we don't execute any more gst_iterator_next. In the end it seems the GStreamer guys have implemented the iterator in an easy way for the developer, avoiding to have deal with reffing and unreffing |
OK I agree this is confusing because not freeing the GValue on each iteration means that a dangling reference is left, which just happens to coincide with the reference we need. But this, even if it works, is really working a bit against the intended use. TL;DR: Please use I myself wasn't sure of how this API should be used, but now have a better picture: the GValue that is returned after each gst_iterator_next must be "freed" (released):
Also, check the intro of GstIterator, this was the clearest to me:
Where the GValue is reset on each iteration, and unset (which releases everything) in the end. I think the remaining reference you noticed, would be cleared out just at this point. Otherwise, our object would be left with an extra reference that in principle belongs to the |
(cherry picked from commit a0a036dd42bd79e04969f2eb1f511689412c398b)
Just updated the handling to make use of the g_value_dup_object. I see it is more clear now |
@slabajo I thought that instead of having a custom implementation to search for the elements, it would be easier to maintain if we have the missing function Also, this is even clearer code, as we can assume just a single element of the given type, so the first iterator result is already the one we're looking for. Please enable the option to allow maintainer commits to your Pull Request: https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/working-with-forks/allowing-changes-to-a-pull-request-branch-created-from-a-fork |
For some reason the allow maintainer commit option does not appear for me, sorry for that |
OK it seems a limitation of GitHub itself: isaacs/github#1681 For some reason they allow the option for user-owned forks, but not for organization-owned ones. So I can only accept the PR and later make the changes I was talking about. |
OK the changes I was talking about are pushed now: cb3ca0f It works by assuming that, given an iterator that filters by factory name, the very first result should be both of a) The element we're looking for. |
## What is the current behavior you want to change? This change is related to a previous PR in #37 More specifically this change covers a use case not covered in the previous PR. This is as follows: - When Kurento is set as DTLS server it may happen that the remote peer of the WebRTC connection reaches to ICE connected state before Kurento does. - The problem appears when not only the remote peer gets ICE connected before but when the peer sends the DTLS Client Hello and it arrives before the WebRTCEndpoint in Kurento has reached the ICE connected state. - If this happens, the DTLS Client hello is received in the nicesrc element from the Webrtctransportsrc and it is relayed to the dtlssrtpdec element. This in turns starts DTLS handshake and sends back a DTLS Server hello to the nicesink element. But, and this is the real problem, the nicesink finds the ICE connection not yet established and silently drops the DTLS server hello. - When the DTLS timeout is up (1 second this first time, but doubling each time), the endpoint will resend again the DTLS server hello packet, and hopefully this time it will find the ICE connection established and the DTLS server hello will be delivered to the remote peer. If not, it will try again on the next timeout. - The problem is that each timeout introduces some additional delay in the WebRTC connection establishment. - In many cases that we have observed, the DTLS Client hello just arrives a few milliseconds before the ICE gets CONNECTED in WebRTCEndpoint. But the impact is that those few miliseconds will make the connection to delay around 1 second. This problem has a lesser impact than the previous PR, but in the end it is worth improving it. ## What is the new behavior provided by this change? - This change only takes effect when the WebRTCEndpoint is configured as DTLS server (waiter for DTLS handshake) - It just captures all packets coming from the nicesrc element to the dtlssrpdec and stores them until the ICE gets connected. - A signal is connected so that when ICE connection changes state, and the new state is connected, it gets the temporary stored buffers and delivers them to the dtlssrtpdec element, thus ensuring the DTLS handshake process only takes place when the ICE connection is established. According to our observations there is only one possible buffer stored that corresponds to the DTLS Client hello received from remote peer. Also, we noticed that if in the same call that notifies ICE connection we delivered the stored DTLS client hello, the answer (DTLS server hello) still finds the ICE connection not usable, so to avoid that, we just make that delivery asynchronously in a separate thread 10 ms later. ## How has this been tested? IT has been tested with automatic tests that cannot yet be used in this Kurento version as they need GStreamer 1.18 to work. We have also tested it in real environmentes capturing network traffic to see that the change causes the desired behaviour.
## What is the current behavior you want to change? This change is related to a previous PR in #37 More specifically this change covers a use case not covered in the previous PR. This is as follows: - When Kurento is set as DTLS server it may happen that the remote peer of the WebRTC connection reaches to ICE connected state before Kurento does. - The problem appears when not only the remote peer gets ICE connected before but when the peer sends the DTLS Client Hello and it arrives before the WebRTCEndpoint in Kurento has reached the ICE connected state. - If this happens, the DTLS Client hello is received in the nicesrc element from the Webrtctransportsrc and it is relayed to the dtlssrtpdec element. This in turns starts DTLS handshake and sends back a DTLS Server hello to the nicesink element. But, and this is the real problem, the nicesink finds the ICE connection not yet established and silently drops the DTLS server hello. - When the DTLS timeout is up (1 second this first time, but doubling each time), the endpoint will resend again the DTLS server hello packet, and hopefully this time it will find the ICE connection established and the DTLS server hello will be delivered to the remote peer. If not, it will try again on the next timeout. - The problem is that each timeout introduces some additional delay in the WebRTC connection establishment. - In many cases that we have observed, the DTLS Client hello just arrives a few milliseconds before the ICE gets CONNECTED in WebRTCEndpoint. But the impact is that those few miliseconds will make the connection to delay around 1 second. This problem has a lesser impact than the previous PR, but in the end it is worth improving it. ## What is the new behavior provided by this change? - This change only takes effect when the WebRTCEndpoint is configured as DTLS server (waiter for DTLS handshake) - It just captures all packets coming from the nicesrc element to the dtlssrpdec and stores them until the ICE gets connected. - A signal is connected so that when ICE connection changes state, and the new state is connected, it gets the temporary stored buffers and delivers them to the dtlssrtpdec element, thus ensuring the DTLS handshake process only takes place when the ICE connection is established. According to our observations there is only one possible buffer stored that corresponds to the DTLS Client hello received from remote peer. Also, we noticed that if in the same call that notifies ICE connection we delivered the stored DTLS client hello, the answer (DTLS server hello) still finds the ICE connection not usable, so to avoid that, we just make that delivery asynchronously in a separate thread 10 ms later. ## How has this been tested? IT has been tested with automatic tests that cannot yet be used in this Kurento version as they need GStreamer 1.18 to work. We have also tested it in real environmentes capturing network traffic to see that the change causes the desired behaviour.
What is the current behavior you want to change?
Current Kurento WebRTC connection introduces unneeded time to complete connection when using STUN or TURN candidates.
DTLS is started by the peer acting as client (with property "is-client" to TRUE) sending an initial DTLS Hello packet. That packet should be responded by the other peer and exchange of keys will happen. If the other peer does not respond, the client will wait for an amount of time before resending DTLS Hello packet. That amount of time starts in 1 second and doubles on each retry, so the retries comes at 1 second, then 2 seconds, then 4, and so on.
In KMS the DTLS connection is managed by the KmsWebrtcTransportSink component, more specifically by the embbeded dtlssrtpenc component. When instantiated in a KmsWebrtcTransportSinkNice component, the sending is managed by a nicesink element associated to the niceagent of the connection.
The problem appears because dtlssrtpenc element initiates DTLS connection as soon as it reaches the PAUSED or PLAYING state, and this always happens before the ICE negotiation has reached to a first valid candidate pair, at least when no HOST valid candidates are found. When this happens, the first DTLS Hello packet is silently dropped by the nicesink as there is no ICE connection established yet. And the timeout for next DTLS Hello starts to run.
The outcome is that when using STUN or TURN candidates, once a first valid pair is found, one or more DTLS Hello packets have already been sent, and as the timeout doubles each retry, it is likely that after ICE connection is established waiting for next retry will take a similar time to the what it took to establish ICE connection.
What is the new behavior provided by this change?
This change consist on the following modifications:
How has this been tested?
It has been tested building a test that is not included because it uses GStreamer 1.18 components to monitor when DTLS connection state changes (DTLS connection state is introduced in GStreamer 1.17)
Also the current tests have been validated, incidentally we have found (and provided a workaround) in the datachannel test in test_webrtcendpoint a race condition when releasing resources after test is finished.
Also we have verified the change running current KMS tutorials with the change incorporated.
Types of changes
Checklist