Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

My video and opponent video is not displaying #526

Closed
mouli457 opened this issue Jul 17, 2020 · 5 comments
Closed

My video and opponent video is not displaying #526

mouli457 opened this issue Jul 17, 2020 · 5 comments
Assignees

Comments

@mouli457
Copy link

I am facing as show in image.Please suggest sample code for latest twilio video configuration.

Screenshot 2020-07-17 at 3 14 02 PM

@paynerc
Copy link
Contributor

paynerc commented Jul 17, 2020

@mouli457,

You can use the TVIVideoTrackPublication.videoTrack method to get properly typed TVIVideoTrack objects.

Let me know if you have any further questions.

Ryan

@paynerc paynerc self-assigned this Jul 17, 2020
@mouli457
Copy link
Author

mouli457 commented Jul 20, 2020

Hai @paynerc

My issue is when opponent was connected only audio is coming and showing error as shown in above question.My complete code shown below(passing access token).Please correct my code.

 import UIKit
import TwilioVideo

class ViewController: UIViewController {

// MARK:- View Controller Members

// Configure access token manually for testing, if desired! Create one manually in the console
// at https://www.twilio.com/console/video/runtime/testing-tools
var accessToken = "TWILIO_ACCESS_TOKEN"

// Configure remote URL to fetch token from
var tokenUrl = "http://localhost:8000/token.php"
var roomName = String()

// Video SDK components
var room: TVIRoom?
var camera: TVICameraSource?
var localVideoTrack: TVIVideoTrack?
var localAudioTrack: TVILocalAudioTrack?
var remoteParticipant: TVIParticipant?
var remoteView: TVIVideoView?

// MARK:- UI Element Outlets and handles

// `VideoView` created from a storyboard

@IBOutlet weak var previewView: TVIVideoView!
@IBOutlet weak var connectButton: UIButton!
@IBOutlet weak var disconnectButton: UIButton!
@IBOutlet weak var messageLabel: UILabel!
@IBOutlet weak var roomTextField: UITextField!
@IBOutlet weak var roomLine: UIView!
@IBOutlet weak var roomLabel: UILabel!
@IBOutlet weak var micButton: UIButton!
deinit {
    // We are done with camera
    if let camera = self.camera {
        camera.stopCapture()
        self.camera = nil
    }
}

// MARK:- UIViewController
override func viewDidLoad() {
    super.viewDidLoad()
    
    self.title = "QuickStart"
    self.messageLabel.adjustsFontSizeToFitWidth = true;
    self.messageLabel.minimumScaleFactor = 0.75;

    if PlatformUtils.isSimulator {
        self.previewView.removeFromSuperview()
    } else {
        // Preview our local camera track in the local video preview view.
        self.startPreview()
     } 
    
    // Disconnect and mic button will be displayed when the Client is connected to a Room.
    self.disconnectButton.isHidden = true
    self.micButton.isHidden = true
    
    self.roomTextField.autocapitalizationType = .none
    self.roomTextField.delegate = self
    
    let tap = UITapGestureRecognizer(target: self, action: #selector(ViewController.dismissKeyboard))
    self.view.addGestureRecognizer(tap)
    
    
}



override var prefersHomeIndicatorAutoHidden: Bool {
    return self.room != nil
}


 


func setupRemoteVideoView() {
    // Creating `VideoView` programmatically
    self.remoteView = TVIVideoView(frame: CGRect.zero, delegate: self)

    self.view.insertSubview(self.remoteView!, at: 0)
    
    // `VideoView` supports scaleToFill, scaleAspectFill and scaleAspectFit
    // scaleAspectFit is the default mode when you create `VideoView` programmatically.
    self.remoteView!.contentMode = .scaleAspectFit;

    let centerX = NSLayoutConstraint(item: self.remoteView!,
                                     attribute: NSLayoutConstraint.Attribute.centerX,
                                     relatedBy: NSLayoutConstraint.Relation.equal,
                                     toItem: self.view,
                                     attribute: NSLayoutConstraint.Attribute.centerX,
                                     multiplier: 1,
                                     constant: 0);
    self.view.addConstraint(centerX)
    let centerY = NSLayoutConstraint(item: self.remoteView!,
                                     attribute: NSLayoutConstraint.Attribute.centerY,
                                     relatedBy: NSLayoutConstraint.Relation.equal,
                                     toItem: self.view,
                                     attribute: NSLayoutConstraint.Attribute.centerY,
                                     multiplier: 1,
                                     constant: 0);
    self.view.addConstraint(centerY)
    let width = NSLayoutConstraint(item: self.remoteView!,
                                   attribute: NSLayoutConstraint.Attribute.width,
                                   relatedBy: NSLayoutConstraint.Relation.equal,
                                   toItem: self.view,
                                   attribute: NSLayoutConstraint.Attribute.width,
                                   multiplier: 1,
                                   constant: 0);
    self.view.addConstraint(width)
    let height = NSLayoutConstraint(item: self.remoteView!,
                                    attribute: NSLayoutConstraint.Attribute.height,
                                    relatedBy: NSLayoutConstraint.Relation.equal,
                                    toItem: self.view,
                                    attribute: NSLayoutConstraint.Attribute.height,
                                    multiplier: 1,
                                    constant: 0);
    self.view.addConstraint(height)
}



// MARK:- IBActions
@IBAction func connect(sender: AnyObject) {
   // Configure access token either from server or manually.
        // If the default wasn't changed, try fetching from server.
        if (accessToken == "TWILIO_ACCESS_TOKEN") {
            do {
                accessToken = try TokenUtils.fetchToken(url: tokenUrl)
            } catch {
                let message = "Failed to fetch access token"
                logMessage(messageText: message)
                return
            }
        }
        
        // Prepare local media which we will share with Room Participants.
        self.prepareLocalMedia()
        
        // Preparing the connect options with the access token that we fetched (or hardcoded).
        let connectOptions = TVIConnectOptions(token: accessToken) { (builder) in
            
            // Use the local media that we prepared earlier.
            builder.audioTracks = [TVIAudioTrack]() as! [TVILocalAudioTrack]
            builder.videoTracks = [TVIVideoTrack]() as! [TVILocalVideoTrack]
            
            // The name of the Room where the Client will attempt to connect to. Please note that if you pass an empty
            // Room `name`, the Client will create one for you. You can get the name or sid from any connected Room.
            builder.roomName = self.roomTextField.text
        }
        
        // Connect to the Room using the options we provided.
    room = TwilioVideo.connect(with: connectOptions, delegate: self)
        
        logMessage(messageText: "Attempting to connect to room \(String(describing: self.roomTextField.text))")
        
        self.showRoomUI(inRoom: true)
        self.dismissKeyboard()
    }
@IBAction func disconnect(sender: AnyObject) {
    self.room!.disconnect()
    logMessage(messageText: "Attempting to disconnect from room \(room!.name)")
}

@IBAction func toggleMic(sender: AnyObject) {
    if (self.localAudioTrack != nil) {
        self.localAudioTrack?.isEnabled = !(self.localAudioTrack?.isEnabled)!
        
        // Update the button title
        if (self.localAudioTrack?.isEnabled == true) {
            self.micButton.setTitle("Mute", for: .normal)
        } else {
            self.micButton.setTitle("Unmute", for: .normal)
        }
    }
}

// MARK:- Private
func startPreview() {
    if PlatformUtils.isSimulator {
        return
    }

    let frontCamera = TVICameraSource.captureDevice(for: .front)
    let backCamera = TVICameraSource.captureDevice(for: .back)

    if (frontCamera != nil || backCamera != nil) {

        let options = TVICameraSourceOptions { (builder) in
            // To support building with Xcode 10.x.
            #if XCODE_1100
            if #available(iOS 13.0, *) {
                // Track UIWindowScene events for the key window's scene.
                // The example app disables multi-window support in the .plist (see UIApplicationSceneManifestKey).
                builder.orientationTracker = UserInterfaceTracker(scene: UIApplication.shared.keyWindow!.windowScene!)
            }
            #endif
        }
        // Preview our local camera track in the local video preview view.
        camera = TVICameraSource(options: options, delegate: (self as TVICameraSourceDelegate))
        localVideoTrack = TVILocalVideoTrack(source: camera!, enabled: true, name: "Camera")

        // Add renderer to video track for local preview
        localVideoTrack!.addRenderer(self.previewView)
        logMessage(messageText: "Video track created")

        if (frontCamera != nil && backCamera != nil) {
            // We will flip camera on tap.
            let tap = UITapGestureRecognizer(target: self, action: #selector(ViewController.flipCamera))
            self.previewView.addGestureRecognizer(tap)
        }

        camera!.startCapture(with: frontCamera != nil ? frontCamera! : backCamera!) { (captureDevice, videoFormat, error) in
            if let error = error {
                self.logMessage(messageText: "Capture failed with error.\ncode = \((error as NSError).code) error = \(error.localizedDescription)")
            } else {
                self.previewView.shouldMirror = (captureDevice.position == .front)
            }
        }
    }
    else {
        self.logMessage(messageText:"No front or back capture device found!")
    }
}

@objc func flipCamera() {
    var newDevice: AVCaptureDevice?

    if let camera = self.camera, let captureDevice = camera.device {
        if captureDevice.position == .front {
            newDevice = TVICameraSource.captureDevice(for: .back)
        } else {
            newDevice = TVICameraSource.captureDevice(for: .front)
        }

        if let newDevice = newDevice {
            camera.select(newDevice) { (captureDevice, videoFormat, error) in
                if let error = error {
                    self.logMessage(messageText: "Error selecting capture device.\ncode = \((error as NSError).code) error = \(error.localizedDescription)")
                } else {
                    self.previewView.shouldMirror = (captureDevice.position == .front)
                }
            }
        }
    }
}

  func prepareLocalMedia() {

    // We will share local audio and video when we connect to the Room.

    // Create an audio track.
    if (localAudioTrack == nil) {
        localAudioTrack = TVILocalAudioTrack(options: nil, enabled: true, name: "Microphone")

        if (localAudioTrack == nil) {
            logMessage(messageText: "Failed to create audio track")
        }
    }

    // Create a video track which captures from the camera.
    if (localVideoTrack == nil) {
        self.startPreview()
    }
    }

// Update our UI based upon if we are in a Room or not
func showRoomUI(inRoom: Bool) {
    self.connectButton.isHidden = inRoom
    self.roomTextField.isHidden = inRoom
    self.roomLine.isHidden = inRoom
    self.roomLabel.isHidden = inRoom
    self.micButton.isHidden = !inRoom
    self.disconnectButton.isHidden = !inRoom
    self.navigationController?.setNavigationBarHidden(inRoom, animated: true)
    UIApplication.shared.isIdleTimerDisabled = inRoom

    // Show / hide the automatic home indicator on modern iPhones.
    self.setNeedsUpdateOfHomeIndicatorAutoHidden()
}

@objc func dismissKeyboard() {
    if (self.roomTextField.isFirstResponder) {
        self.roomTextField.resignFirstResponder()
    }
}

func logMessage(messageText: String) {
    NSLog(messageText)
    messageLabel.text = messageText
}

func renderRemoteParticipant(participant : TVIParticipant) -> Bool {
    // This example renders the first subscribed RemoteVideoTrack from the RemoteParticipant.
    let videoPublications = participant.videoTracks
    for publication in videoPublications {
        if let subscribedVideoTrack = publication.track,
            publication.isTrackEnabled {
            setupRemoteVideoView()
            subscribedVideoTrack.addRenderer(self.remoteView!)
            self.remoteParticipant = participant
            return true
        }
    }
    return false
}



func renderRemoteParticipants(participants : Array<TVIParticipant>) {
    for participant in participants {
        // Find the first renderable track.
        if participant.videoTracks.count > 0,
            renderRemoteParticipant(participant: participant) {
            break
        }
    }
}

func cleanupRemoteParticipant() {
    if self.remoteParticipant != nil {
        self.remoteView?.removeFromSuperview()
        self.remoteView = nil
        self.remoteParticipant = nil
    }
}
}

  // MARK:- UITextFieldDelegate
 extension ViewController : UITextFieldDelegate {
   func textFieldShouldReturn(_ textField: UITextField) -> Bool {
    self.connect(sender: textField)
    return true
  }
  }

  // MARK:- RoomDelegate
  extension ViewController : TVIRoomDelegate {
    func roomDidConnect(room: TVIRoom) {
    logMessage(messageText: "Connected to room \(room.name) as \(room.localParticipant?.identity ?? "")")

    // This example only renders 1 RemoteVideoTrack at a time. Listen for all events to decide which track to render.
    for remoteParticipant in room.remoteParticipants {
        remoteParticipant.delegate = self
    }
    }

func roomDidDisconnect(room: TVIRoom, error: Error?) {
    logMessage(messageText: "Disconnected from room \(room.name), error = \(String(describing: error))")
    
    self.cleanupRemoteParticipant()
    self.room = nil
    
    self.showRoomUI(inRoom: false)
    }

func roomDidFailToConnect(room: TVIRoom, error: Error) {
    logMessage(messageText: "Failed to connect to room with error = \(String(describing: error))")
    self.room = nil
    
    self.showRoomUI(inRoom: false)
    }

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

func roomDidReconnect(room: TVIRoom) {
    logMessage(messageText: "Reconnected to room \(room.name)")
}

func participantDidConnect(room: TVIRoom, participant: TVIParticipant) {
    // Listen for events from all Participants to decide which RemoteVideoTrack to render.

    logMessage(messageText: "Participant \(participant.identity) connected with \(participant.audioTracks.count) audio and \(participant.videoTracks.count) video tracks")
}

func participantDidDisconnect(room: TVIRoom, participant: TVIParticipant) {
    logMessage(messageText: "Room \(room.name), Participant \(participant.identity) disconnected")

    // Nothing to do in this example. Subscription events are used to add/remove renderers.
}

}

  // MARK:- RemoteParticipantDelegate
  extension ViewController : TVIRemoteParticipantDelegate {

func remoteParticipantDidPublishVideoTrack(participant: TVIParticipant, publication: TVIVideoTrackPublication) {
    // Remote Participant has offered to share the video Track.
    
    logMessage(messageText: "Participant \(participant.identity) published \(publication.trackName) video track")
}

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

    logMessage(messageText: "Participant \(participant.identity) unpublished \(publication.trackName) video track")
}

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

    logMessage(messageText: "Participant \(participant.identity) published \(publication.trackName) audio track")
}

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

    logMessage(messageText: "Participant \(participant.identity) unpublished \(publication.trackName) audio track")
}

func didSubscribeToVideoTrack(videoTrack: TVIVideoTrack, publication: TVIVideoTrackPublication, participant: TVIParticipant) {
    // The LocalParticipant is subscribed to the RemoteParticipant's video Track. Frames will begin to arrive now.

    logMessage(messageText: "Subscribed to \(publication.trackName) video track for Participant \(participant.identity)")

    if (self.remoteParticipant == nil) {
        _ = renderRemoteParticipant(participant: participant)
    }
}

func didUnsubscribeFromVideoTrack(videoTrack: TVIVideoTrack, publication: TVIVideoTrackPublication, participant: TVIParticipant) {
    // We are unsubscribed from the remote Participant's video Track. We will no longer receive the
    // remote Participant's video.
    
    logMessage(messageText: "Unsubscribed from \(publication.trackName) video 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.firstIndex(of: participant as! TVIRemoteParticipant) {
            remainingParticipants.remove(at: index)
            renderRemoteParticipants(participants: remainingParticipants)
        }
    }
    }

func didSubscribeToAudioTrack(audioTrack: TVIAudioTrack, publication: TVIAudioTrackPublication, participant: TVIParticipant) {
    // We are subscribed to the remote Participant's audio Track. We will start receiving the
    // remote Participant's audio now.
   
    logMessage(messageText: "Subscribed to \(publication.trackName) audio track for Participant \(participant.identity)")
}

func didUnsubscribeFromAudioTrack(audioTrack: TVIAudioTrack, publication: TVIAudioTrackPublication, participant: TVIParticipant) {
    // We are unsubscribed from the remote Participant's audio Track. We will no longer receive the
    // remote Participant's audio.
    logMessage(messageText: "Unsubscribed from \(publication.trackName) audio track for Participant \(participant.identity)")
}

func remoteParticipantDidEnableVideoTrack(participant: TVIParticipant, publication: TVIVideoTrackPublication) {
    logMessage(messageText: "Participant \(participant.identity) enabled \(publication.trackName) video track")
}

func remoteParticipantDidDisableVideoTrack(participant: TVIParticipant, publication: TVIVideoTrackPublication) {
    logMessage(messageText: "Participant \(participant.identity) disabled \(publication.trackName) video track")
}

func remoteParticipantDidEnableAudioTrack(participant: TVIParticipant, publication: TVIAudioTrackPublication) {
    logMessage(messageText: "Participant \(participant.identity) enabled \(publication.trackName) audio track")
}

func remoteParticipantDidDisableAudioTrack(participant: TVIParticipant, publication: TVIAudioTrackPublication) {
    logMessage(messageText: "Participant \(participant.identity) disabled \(publication.trackName) audio track")
}

func didFailToSubscribeToAudioTrack(publication: TVIAudioTrackPublication, error: Error, participant: TVIParticipant) {
    logMessage(messageText: "FailedToSubscribe \(publication.trackName) audio track, error = \(String(describing: error))")
}

func didFailToSubscribeToVideoTrack(publication: TVIVideoTrackPublication, error: Error, participant: TVIParticipant) {
    logMessage(messageText: "FailedToSubscribe \(publication.trackName) video track, error = \(String(describing: error))")
}
}

 // MARK:- VideoViewDelegate
extension ViewController : TVIVideoViewDelegate {
func videoViewDimensionsDidChange(view: TVIVideoView, dimensions: CMVideoDimensions) {
    self.view.setNeedsLayout()
}
}

 // MARK:- CameraSourceDelegate
 extension ViewController : TVICameraSourceDelegate {
func cameraSourceDidFail(source: TVICameraSource, error: Error) {
    logMessage(messageText: "Camera source failed with error: \(error.localizedDescription)")
}
}

@paynerc
Copy link
Contributor

paynerc commented Jul 20, 2020

First question that I have is what version of TwilioVideo are you using? From the code it would appear to be 2.x as we have removed the need for the TVI prefix with our classes in Swift starting with 3.0.0.

The methods defined in RemoteParticipantDelegte all pass in instances of RemoteParticipant and not the base class Participant. That is the first thing I am seeing here. If you fix that, then I would make the following changes:

func renderRemoteParticipant(participant : RemoteParticipant) -> Bool {
    // This example renders the first subscribed RemoteVideoTrack from the RemoteParticipant.
    let videoPublications = participant.remoteVideoTracks
    for publication in videoPublications {
        if let subscribedVideoTrack = publication.remoteTrack,
            publication.isTrackEnabled {
            setupRemoteVideoView()
            subscribedVideoTrack.addRenderer(self.remoteView!)
            self.remoteParticipant = participant
            return true
        }
    }
    return false
}



func renderRemoteParticipants(participants : Array<RemoteParticipant>) {
    for participant in participants {
        // Find the first renderable track.
        if participant.videoTracks.count > 0,
            renderRemoteParticipant(participant: participant) {
            break
        }
    }
}

@mouli457
Copy link
Author

Actually,My problem is I install TwilioVideo through pods and I use example code in ViewController.swift but i got so many errors.Then I change some keywords with TVI prefix.All errors are fixed but my question issue not fixed and I comment that line and run my project,It's work but opponent video is not displaying.I am using (3.2.5)version.Please tell me pod name which is used in GitHub example or send me latest example code.Thanks in advance.

@paynerc
Copy link
Contributor

paynerc commented Jul 24, 2020

@mouli457,

I see that you have opened issue #530 so I am assuming that you have gotten things to install and are no longer stuck with this issue. I am going to close this ticket and we can continue to work through #53

Ryan

@paynerc paynerc closed this as completed Jul 24, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants