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:
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:
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.
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).
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!
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.
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.
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)
}
}