twilio / video-quickstart-ios

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

Some of Room delegate methods were never calling. #489

Closed sureshmopidevi closed 4 years ago

sureshmopidevi commented 4 years ago

Xcode 11.4.1 Device: iPhone 6s SDK version: 3.2

When i connected to room

  1. roomDidConnect was calling and getting remote stream data like video, audio.
  2. In Remote participant Delegate - didSubscribeToAudioTrack, didUnsubscribeFromVideoTrack were calling

participantDidConnect was never calling.

When remote user disconnects

  1. participantDidDisconnect, didUnsubscribeFromVideoTrack,didSubscribeToAudioTrack was never calling.
room = TwilioVideoSDK.connect(options: options, delegate: self)

Room delegate

extension TwilioController: RoomDelegate {
    func roomDidConnect(room: Room) {
        room.remoteParticipants.forEach({$0.delegate = self})
    }

    func roomDidDisconnect(room: Room, error: Error?) {
        print("Disconnected from room \(room.name), error = \(String(describing: error))")
        self.cleanupRemoteParticipant()
        self.room = nil
    }

    func roomDidFailToConnect(room _: Room, error: Error) {
        print("Failed to connect to room with error = \(String(describing: error))")
        self.room = nil
    }

    func roomIsReconnecting(room: Room, error: Error) {
        print("Reconnecting to room \(room.name), error = \(String(describing: error))")
    }

    func roomDidReconnect(room: Room) {
        print("Reconnected to room \(room.name)")
    }

    func participantDidConnect(room: Room, participant: RemoteParticipant) {
        // Listen for events from all Participants to decide which RemoteVideoTrack to render.
        participant.delegate = self
        print("Participant \(participant.identity) connected with \(participant.remoteAudioTracks.count) audio and \(participant.remoteVideoTracks.count) video tracks")
    }

    func participantDidDisconnect(room: Room, participant: RemoteParticipant) {
        print("Room \(room.name), Participant \(participant.identity) disconnected")
        // Nothing to do in this example. Subscription events are used to add/remove renderers.
    }
}

Remote Participant delegate


extension TwilioController: RemoteParticipantDelegate {
    func remoteParticipantDidPublishVideoTrack(participant: RemoteParticipant, publication: RemoteVideoTrackPublication) {
        // Remote Participant has offered to share the video Track.
        print("Participant \(participant.identity) published \(publication.trackName) video track")
    }

    func remoteParticipantDidUnpublishVideoTrack(participant: RemoteParticipant, publication: RemoteVideoTrackPublication) {
        // Remote Participant has stopped sharing the video Track.

        print("Participant \(participant.identity) unpublished \(publication.trackName) video track")
    }

    func remoteParticipantDidPublishAudioTrack(participant: RemoteParticipant, publication: RemoteAudioTrackPublication) {
        // Remote Participant has offered to share the audio Track.

        print("Participant \(participant.identity) published \(publication.trackName) audio track")
    }

    func remoteParticipantDidUnpublishAudioTrack(participant: RemoteParticipant, publication: RemoteAudioTrackPublication) {
        // Remote Participant has stopped sharing the audio Track.

        print("Participant \(participant.identity) unpublished \(publication.trackName) audio track")
    }

    func didSubscribeToVideoTrack(videoTrack _: RemoteVideoTrack, publication: RemoteVideoTrackPublication, participant: RemoteParticipant) {
        // The LocalParticipant is subscribed to the RemoteParticipant's video Track. Frames will begin to arrive now.
        print("Subscribed to \(publication.trackName) video track for Participant \(participant.identity)")
        if self.remoteParticipant == nil {
            _ = renderRemoteParticipant(participant: participant)
        }
    }

    func didUnsubscribeFromVideoTrack(videoTrack _: RemoteVideoTrack, publication: RemoteVideoTrackPublication, participant: RemoteParticipant) {
        print("Unsubscribed from \(publication.trackName) video track for Participant \(participant.identity)")
    }

    func didSubscribeToAudioTrack(audioTrack _: RemoteAudioTrack, publication: RemoteAudioTrackPublication, participant: RemoteParticipant) {
        print("Subscribed to \(publication.trackName) audio track for Participant \(participant.identity)")
    }

    func didUnsubscribeFromAudioTrack(audioTrack _: RemoteAudioTrack, publication: RemoteAudioTrackPublication, participant: RemoteParticipant) {
        print("Unsubscribed from \(publication.trackName) audio track for Participant \(participant.identity)")
        if self.remoteParticipant == participant {
            cleanupRemoteParticipant()
            // Find another Participant video to render, if possible.
            if var remainingParticipants = room?.remoteParticipants,
                let index = remainingParticipants.index(of: participant) {
                remainingParticipants.remove(at: index)
                renderRemoteParticipants(participants: remainingParticipants)
            }
        }
    }

    func remoteParticipantDidEnableVideoTrack(participant: RemoteParticipant, publication: RemoteVideoTrackPublication) {
        print("Participant \(participant.identity) enabled \(publication.trackName) video track")
    }

    func remoteParticipantDidDisableVideoTrack(participant: RemoteParticipant, publication: RemoteVideoTrackPublication) {
        showConectionStatus(text: "Video Paused")
        print("Participant \(participant.identity) disabled \(publication.trackName) video track")
    }

    func remoteParticipantDidEnableAudioTrack(participant: RemoteParticipant, publication: RemoteAudioTrackPublication) {
        print("Participant \(participant.identity) enabled \(publication.trackName) audio track")
    }

    func remoteParticipantDidDisableAudioTrack(participant: RemoteParticipant, publication: RemoteAudioTrackPublication) {
        print("Participant \(participant.identity) disabled \(publication.trackName) audio track")
    }

    func didFailToSubscribeToAudioTrack(publication: RemoteAudioTrackPublication, error: Error, participant _: RemoteParticipant) {
        print("FailedToSubscribe \(publication.trackName) audio track, error = \(String(describing: error))")
    }

    func didFailToSubscribeToVideoTrack(publication: RemoteVideoTrackPublication, error: Error, participant _: RemoteParticipant) {
        print("FailedToSubscribe \(publication.trackName) video track, error = \(String(describing: error))")
    }
}

Did i missed something. Please help me to figure out the issue. Thanks.

paynerc commented 4 years ago

@sureshmopidevi,

Looking at the RoomDelegate code you pasted, there is an error with this line:

 func roomDidReconnect(room: Room) {
        print("Reconnected to room \(room.name)"
    }

And that appears to be bleeding into the following two definitions. I'm not sure if that is how it is in your actual file of if that was just a typo in the Git issue. If it is is your actual file, that might be why the following two delegate methods are not being invoked.

Ryan

sureshmopidevi commented 4 years ago

@paynerc it's a typo in git issue.

paynerc commented 4 years ago

@sureshmopidevi,

OK. I wasn't sure how that would have even compiled otherwise. So if I am correct in understanding what you are seeing...

  1. You have participant A who joins a room
    • roomDidConnect() is called.
  2. Participant B joins the same room
    • participantDidConnect() was never called.
  3. Participant B leaves the room
    • participantDidDisconnect() was never called.
  4. Participant A leaves the room
    • roomDidDisconnect() was called?

What is TwilioController? What is the lifetime of this object? From a look at the implementations listed above, it would seem like these delegates should be getting called. Room.delegate and RemoteParticipant.delegate maintains a weak references to the object passed in. I am wondering if the TwilioConroller object is instantiated and passed in to the TwilioVideoSDK.connect() method, and eventually goes out of scope and is deallocated if nothing else is holding a strong reference to it. I am not sure if this is what is happening here, but without seeing the actual code, it is a possibility.

Also, do you have any debug level log files that I could look at?

If you don't feel comfortable publicly sharing code or log files, you can open a Twilio support ticket by emailing support@twilio.com and mention that I asked you to send information, and include this GitHub issue and it should get routed to me.

Ryan

sureshmopidevi commented 4 years ago

@paynerc I have workaround and i assumed that data track causing the issue.

Connection options

func setupConnectionOptions(roomName: String, token: String) -> ConnectOptions {
        return ConnectOptions(token: token) { builder in
            if let videoTrack = self.localVideoTrack {
                builder.videoTracks = [videoTrack]
            }
            if let audioTrack = self.localAudioTrack {
                builder.audioTracks = [audioTrack]
            }

            if let dataTask = self.localDataTrack {
                builder.dataTracks = [dataTask]
            }

            builder.roomName = roomName
        }
    }

Data track was assigning to builder by null check. but when i have the following ⬇️ code, video/audio unsubscribing and participant disconnection was not calling.

if let dataTask = self.localDataTrack {
         builder.dataTracks = [dataTask]
   }

After removing data track from connection options. i was abled to get audio/video unpublishing and participant disconnection call.

Query

Lets say we have 2 users A From web and B from iOS If A end call , participantDidDisconnects calls on B side , and i am disconnecting room. When B ends call. I was calling

room?.disconnect() 

log


Unsubscribed audio track for Participant XXX-XXXX-XXXXX-XXXX Unsubscribed video track for Participant XXX-XXXX-XXXXX-XXXX Disconnected from room room1, error = nil

Room was successfully disconnected for B but call was never ending at A.

paynerc commented 4 years ago

@sureshmopidevi,

That sounds like a potentially serious issue if it is happening repeatedly for you. I would like to see the debug level logs for the run where publishing the data track in the connect options is then causing you further issues as well as the code using to create your data track. I would really like to be able to reproduce the issue that you are seeing. At minimum a Room SID would be helpful so I can do some further investigating.

As far as your second question, you are saying that after calling room.disconnect() on iOS, you receive the roomDidDisconnect() event on iOS, but the JS SDK is not receiving the participantDisconnected event?

Ryan

sureshmopidevi commented 4 years ago

@paynerc We are not using REST API to create rooms, instead we are adding VideoGrant to a dynamic room name by following below guide https://www.twilio.com/docs/video/tutorials/user-identity-access-tokens#javascript So will there be a RoomSid in this case also?

paynerc commented 4 years ago

Yes, absolutely. When you connect to a room the Room SID is provided back in the Room object. You can log this out in your roomDidConnect() callback.

    func roomDidConnect(room: Room) {
        room.remoteParticipants.forEach({$0.delegate = self})
        print("Connected to room \(room.name), Room Sid = \(room.sid)")
    }

If you can reproduce the issue where the data tracks in the connect options is causing issues, please at minimum send a Room SID. As I said, debug level logs would be the most helpful but I understand you may not wish to attach them to this public GitHub issue. As I mentioned before, you can send them to support@twilio.com, reference me and this issue and let me know here that you sent them and I will find the support issue.

Thank you,

Ryan

sureshmopidevi commented 4 years ago

@paynerc , I have sent an email to support@twilio.com along with some log files and required information.

Thanks.

paynerc commented 4 years ago

Thank you, I will keep my eye out for the support issue and will get back to you as soon as possible.

Thank you,

Ryan

paynerc commented 4 years ago

@sureshmopidevi,

I have responded to the support issue. I will move all communications to that medium for the time being and once we come to a resolution I will update this public facing GitHub issue in the case that it may help other developers in the future.

Ryan

paynerc commented 4 years ago

Closing this issue as we discussed in the support ticket that the code is actually working as expected and there are no issues in the SDK.