GoogleWebRTC hangs (freezes) the main thread in swift native app

We have hanging problem (the app freezes due of main thread lock) with our iOS (swift) native app with OpenVidu implementation (which uses GoogleWebRTC under the hood). The specific conditions required: need to join existing room with at least 8 participants already streaming. With 6 participants it happens less often and almost never with less than 6. It doesn’t hang if participants join one by one, only if you join the room with all other participants already streaming. This indicates concurrent nature of the issue.

The GoogleWebRTC hangs on setRemoteDescription call:

func setRemoteDescription(sdpAnswer: String) {
    let sessionDescription: RTCSessionDescription = RTCSessionDescription(type: RTCSdpType.answer, sdp: sdpAnswer)
    self.peerConnection!.setRemoteDescription(sessionDescription, completionHandler: {(error) in
        print("Local Peer Remote Description set: " + error.debugDescription)
    })
}

Screen Shot 2021-05-21 at 11.45.09 AM

As you can see on the screenshot above, the main thread hangs on __psynch_cvwait . No any other threads seems being locked. The lock never releases leaving the app completely frozen.

In the attempt to solve it I was trying the following:

  1. I moved OpenVidu signaling server processing (RPC protocol) from the main thread into separate threads. This only caused the lock now occurs in the one of separate threads I created. It now doesn’t block the UI, but blocks OV signaling. The problem persists.
  2. I added the lock to process each signaling event (participant join event, publish video, etc) synchronously (one by one). This doesn’t help either (it actually made the situation worse).
  3. Instead of using GoogleWebRTC v. 1.1.31999 from Cocoapods, I downloaded the latest GoogleWebRTC sources, built them in release configuration and included into my project. This didn’t help to solve the issue.

Any suggestions/comments would be appreciated. Thanks!

We found some issues in the past similar to your issue.

We detected that if a new participant is trying to subscribe to other participants when joining the session you can have the issues you are facing.

We tried to fix the issue (in the underlying webrtc implementation) waiting several milliseconds between subscriptions.

Can you test it and share the results with us?

Best regards

Yes, I can test it. The issue reproducible about 100% of time, steps to reproduce: establish 7-8 participants to the room with video+audio streams (I do it from Android devices). Then try to join session on iPhone. Please also see the discussion I opened for this on SO: multithreading - GoogleWebRTC hangs (freezes) the main thread in swift native app (OpenVidu) - Stack Overflow

If you want me to test something, please share your code fixes for GoogleWebRTC (if you did it in the source code, it should be in C++ I guess). I can inject them into C++ source code and rebuild. BTW, when I rebuild GoogleWebRTC framework in DEBUG configuration, the issue is no longer reproducible, I guess because DEBUG build do everything much slower, it has a lot of additional checks enabled, which slow down the whole thing. Of course we can’t use DEBUG build of Framework in Production.

Hi @mikeks ,

First of all, i want to know if you’re using our openvidu-ios project or your custom app.

Secondable, We’ve detected a issue related with your problem few months ago. We made a hypothesis which it is that subcribing more than 7-8 users at the same time, some iPhone models had problems. It looks like a resources problem , it looks as if the iPhone was not capable to subscribe to all stream.

I would recommend you apply the following workaround and fixes and test if the problem persist. These fixes are ordered in order of least to most aggressiveness:

  • Save the subscribers in an external array and subsccribe to them in groups of 5 or 6 participants. When the 6th participant has been subscribed, apply a ligth timeout and continue with others.
  • Reduce the media resolution of each participant
  • Set a timeout of X ms of each participant susbription. (We’ve tested with 100 ms and it worked)

Hello, We are using our custom apps, but the OV-related code imported from your iOS example which we have been bought from OpenVidu. The part related to WebRTC is practically imported as is.

I can assure you that this is not the resource problem, because we can stable reproduce the thread lock. I clearly understand the reason why this happens - the main thread locked on setRemoteDescription call. If you looked at the latest screenshot I posted in EDIT 2 on StackOverflow, you will see that 2 internal WebRTC thread (worker thread and signaling thread) are locked in the same kind of mutex, which may possible indicate that worker thread and signaling thread mutually dead-locked. This is just the guess though.

We have quite low signal in terms of data load (240x240, 15fps) and this can’t be related to the lock.

As you said that, could you please, test with the points commented in my previous message?

Yes, at this moment we tested the solution you proposed in Production and it solves the issue. I should say that this looks more like a hack for me, but it works. I added 100ms delay between adding remote participants already in room:

        DispatchQueue.global(qos: .background).async {
            for info in dict.values {
                let remoteParticipant = self.newRemoteParticipant(info: info)
                if let streamId = info.streamId {
                    remoteParticipant.createOffer(completion: {(sdp) in
                        self.receiveVideoFrom(sdp: sdp, remoteParticipant: remoteParticipant, streamId: streamId)
                    })
                } else {
                    print("No streamId")
                }
                Thread.sleep(forTimeInterval: 0.1)
            }
        }