twilio / video-quickstart-ios

Twilio Video Quickstart for iOS
https://www.twilio.com/docs/api/video
MIT License
460 stars 177 forks source link

removeRenderer is not working, due to that memory issues are coming #525

Closed gurupatel closed 3 years ago

gurupatel commented 4 years ago

201 # Description

I am trying to remove old video render & try to add new one, but it is keeping adding & due to that memory issues are coming & app is crashing.

Steps to Reproduce

  1. Adding a remote video by using addRenderer self.localVideoTrack!.addRenderer(remoteView) self.remoteView!.addSubview(remoteView)

  2. Trying to remove that remote video by using removeRenderer (check the method below)

Code

Init : - 
    @IBOutlet var remoteView: VideoView?

Method : - 
func addRemoteVideo(videoTrack: RemoteVideoTrack, name: String) {

        self.lblDominan.text = name

        if (self.remoteView != nil) {

            videoTrack.removeRenderer(self.remoteView!)

            if let remoteView = VideoView.init(frame: CGRect(x: 0, y: 0, width: CGFloat(self.remoteView!.frame.size.width), height: CGFloat(self.remoteView!.frame.size.height)), delegate:self) {

                videoTrack.addRenderer(remoteView)

                self.remoteView!.addSubview(remoteView)

                remoteView.contentMode = .scaleAspectFill
                remoteView.shouldMirror = true
            }
        }
    }

Expected Behavior

It should remove the old rendered video & add new one

Actual Behavior

It is keeping adding new video and increase count by 1 every time, I have check this by printing count

Reproduces How Often

Often

Logs

Debug level logs are helpful when investigating issues. To enable debug level logging, add the following code to your application:

TwilioVideoSDK.setLogLevel(.debug)
// Log output when the issue occurs

Versions

All relevant version information for the issue.

Video iOS SDK

CocoaPods

Xcode

11.5

iOS Version

11 and above

iOS Device

iPhone 8, Simulator

paynerc commented 4 years ago

@gurupatel,

It appears that you have a TVIVideoView set up in Interface builder that is linked as an @IBOutlet to the remoteView instance variable.

Then in your addRemoteVideo(videoTrack:, name:) method you first check to see that remoteView is not nil and then attempt to call removeRenderer() on the newly passed in video track. Then you are creating yet another TVIVideoView, assigning it as the renderer for the supplied video track and then adding it as a subview to the @IBOutlet remoteView instance variable.

You never appear to remove the subviews that you add to the @IBOutlet remoteView instance variable. The resource exhaustion crash you are likely seeing is due to the fact that the @IBOutlet remoteView instance variable of your application lives a very long time and as you add more and more tracks over time, the instance variable is still holding all of those subviews.

There are a few things I would consider:

  1. I don't think you want to keep adding subviews to the remoteView instance variable. If you want a container to add and remove TVIVideoViews from, I would suggest just make the containing view a regular UIView.
  2. You are never actually adding self.remoteView as a renderer to any video track. You are creating a TVIVideoView, adding that object as the renderer to the video track and then adding that view as a subview of self.remoteView. The subsequent calls to videoTrack.removeRenderer(self.remoteView!) are never going to do anything at this point for two possible reasons: a. self.remoteView is not the view being added as the renderer to a video track... The subview is the renderer. When you call removeRenderer it is going to look for the view you pass in, and here, it is the parent, and not the actual rendering view b. You are calling removeRenderer on the newly supplied video track, not the one that was previously being rendered.
  3. It is not necessary to create new TVIVideoViews if you want to reuse the same view. Create the TVIVideoView as you are in interface builder and have it configured as you like. When you are subscribed to a remote video track, call addRenderer on the supplied track and pass in the instance of TVIVideoView. When you unsubscribe from that track, call removeRenderer on the supplied track and pass in the instance of TVIVideoView. When a view is removed as a renderer for a track internally we invalidate and reset the TVIVideoView which will cause it to display a black frame instead of that last rendered video frame.

Let me know if you have any further questions,

Ryan

paynerc commented 4 years ago

@gurupatel,

Haven't heard back from you in a while. Did the answer above help you?

Ryan

paynerc commented 3 years ago

@gurupatel,

Closing this issue, but feel free to reopen it if you are still experiencing the issue.

Ryan