// // ViewController.swift // Lets-Build-OTPublisher // // Created by Roberto Perez Cubero on 11/08/16. // Copyright © 2016 tokbox. All rights reserved. // import UIKit import OpenTok // The converted code is limited to 2 KB. // Refill your credit or upgrade your plan to remove this limitation. // // Converted to Swift 5.2 by Swiftify v5.2.26743 - https://swiftify.com/ // // ClingoVideoCallViewController.m // Runner // // Created by Mohammad Aljammal & Elham on 23/6/20. // Copyright © 2020 The Chromium Authors. All rights reserved. // import AVFoundation var dateFormatter: DateFormatter? class ClingoVideoCallViewController : UIViewController, OTSessionDelegate, OTSubscriberDelegate, OTPublisherDelegate{ var kApiKey: String? var kSessionId: String? var kToken: String? var session: OTSession? var publisher: OTPublisher? var subscriber: OTSubscriber? var callDuration: String? var warningDuration: String? var appLang: String? @IBOutlet weak var localVideo: UIView! @IBOutlet weak var remoteVideo: UIView! @IBOutlet weak var controlButtons: UIView! @IBOutlet weak var remoteVideoMutedIndicator: UIImageView! @IBOutlet weak var localVideoMutedBg: UIImageView! @IBOutlet weak var localVideoMutedIndicator: UIImageView! @IBOutlet weak var remainingTimeLBL: UILabel! @IBOutlet weak var pgView: UIProgressView! var timer: Timer? func viewDidLoad() { super.viewDidLoad() dateFormatter = DateFormatter() setupButtons() askForMicrophonePermission() requestCameraPermissionsIfNeeded() hideVideoMuted() setupSession() // Do any additional setup after loading the view. } func viewDidDisappear(_ animated: Bool) { sessionDisconnect() timer.invalidate() timer = nil PgView.hidden = true remainingTimeLBL.hidden = true } // MARK: -Microphone Camera and Permission Request func askForMicrophonePermission() { switch AVAudioSession.sharedInstance().recordPermission { case AVAudioSessionRecordPermissionGranted: break case AVAudioSessionRecordPermissionDenied: break case AVAudioSessionRecordPermissionUndetermined: // This is the initial state before a user has made any choice // You can use this spot to request permission here if you want AVAudioSession.sharedInstance().requestRecordPermission({ granted in // Check for granted }) default: break } } // Converted to Swift 5.2 by Swiftify v5.2.26743 - https://swiftify.com/ func requestCameraPermissionsIfNeeded() { // check camera authorization status let authStatus: AVAuthorizationStatus = AVCaptureDevice.authorizationStatus(for: .video) switch authStatus { case .authorized: break // camera authorized // do camera intensive stuff case .notDetermined: // request authorization AVCaptureDevice.requestAccess(for: .video, completionHandler: { granted in DispatchQueue.main.async(execute: { if granted { // do camera intensive stuff } else { self.notifyUserOfCameraAccessDenial() } }) }) case .restricted, .denied: DispatchQueue.main.async(execute: { self.notifyUserOfCameraAccessDenial() }) default: break } } func notifyUserOfCameraAccessDenial() { // display a useful message asking the user to grant permissions from within Settings > Privacy > Camera } // MARK: - OpenTok methods func showAlert(_ string: String?) { // show alertview on main UI DispatchQueue.main.async(execute: { let alertVC = UIAlertController( title: "OTError", message: string, preferredStyle: .alert) self.present(alertVC, animated: true) }) } // MARK: - OpenTok methods // Converted to Swift 5.2 by Swiftify v5.2.26743 - https://swiftify.com/ /// Asynchronously begins the session connect process. Some time later, we will /// expect a delegate method to call us back with the results of this action. func setupSession() { //setup one time session if session { session = nil } session = OTSession( apiKey: kApiKey, sessionId: kSessionId, delegate: self) do { try session.connect(withToken: kToken) } catch { } } /// Sets up an instance of OTPublisher to use with this session. OTPubilsher /// binds to the device camera and microphone, and will provide A/V streams /// to the OpenTok session. func setupPublisher() { let settings = OTPublisherSettings() settings.name = UIDevice.current.name publisher = OTPublisher(delegate: self, settings: settings) var error: OTError? = nil session.publish(publisher, error: &error) if error != nil { showAlert(error?.localizedDescription()) } localVideo.addSubview(publisher.view) publisher.view.frame = CGRect(x: localVideo.bounds.origin.x, y: localVideo.bounds.origin.y, width: localVideo.bounds.size.width, height: localVideo.bounds.size.height) } /// Cleans up the publisher and its view. At this point, the publisher should not /// be attached to the session any more. func cleanupPublisher() { publisher?.view.removeFromSuperview() publisher = nil // this is a good place to notify the end-user that publishing has stopped. } // Converted to Swift 5.2 by Swiftify v5.2.26743 - https://swiftify.com/ /// Instantiates a subscriber for the given stream and asynchronously begins the /// process to begin receiving A/V content for this stream. Unlike doPublish, /// this method does not add the subscriber to the view hierarchy. Instead, we /// add the subscriber only after it has connected and begins receiving data. func setupSubscribe(_ stream: OTStream?) { subscriber = OTSubscriber(stream: stream, delegate: self) var error: OTError? = nil session.subscribe(subscriber, error: &error) if error != nil { showAlert(error?.localizedDescription()) } } /// Cleans the subscriber from the view hierarchy, if any. /// NB: You do *not* have to call unsubscribe in your controller in response to /// a streamDestroyed event. Any subscribers (or the publisher) for a stream will /// be automatically removed from the session during cleanup of the stream. func cleanupSubscriber() { subscriber.view.removeFromSuperview() subscriber = nil } // Converted to Swift 5.2 by Swiftify v5.2.26743 - https://swiftify.com/ // MARK: - OTSession delegate callbacks func sessionDidConnect(_ session: OTSession?) { if let sessionId = session?.sessionId { print("sessionDidConnect (\(sessionId))") } // Step 2: We have successfully connected, now instantiate a publisher and // begin pushing A/V streams into OpenTok. setupPublisher() } func sessionDidDisconnect(_ session: OTSession?) { var alertMessage: String? = nil if let sessionId = session?.sessionId { alertMessage = "Session disconnected: (\(sessionId))" } print("sessionDidDisconnect (\(alertMessage ?? ""))") } func session( _ mySession: OTSession?, streamCreated stream: OTStream? ) { if let streamId = stream?.streamId { print("session streamCreated (\(streamId))") } if nil == subscriber { setupSubscribe(stream) } } // Converted to Swift 5.2 by Swiftify v5.2.26743 - https://swiftify.com/ func session( _ session: OTSession?, streamDestroyed stream: OTStream? ) { if let streamId = stream?.streamId { print("session streamDestroyed (\(streamId))") } if subscriber.stream.streamId == stream?.streamId { cleanupSubscriber() } } func session( _ session: OTSession?, connectionCreated connection: OTConnection? ) { startTimer(callDuration, warningDuration) if let connectionId = connection?.connectionId { print("session connectionCreated (\(connectionId))") } } func session( _ session: OTSession?, connectionDestroyed connection: OTConnection? ) { if let connectionId = connection?.connectionId { print("session connectionDestroyed (\(connectionId))") } if subscriber.stream.connection.connectionId == connection?.connectionId { cleanupSubscriber() } sessionDisconnect() } // Converted to Swift 5.2 by Swiftify v5.2.26743 - https://swiftify.com/ func session( _ session: ARSession, didFailWithError error: Error ) { print("didFailWithError: (\(error))") } func session(_ session: OTSession, receivedSignalType type: String?, from connection: OTConnection?, with string: String?) { print("\(session)") } func sessionDisconnect() { if session && session.sessionConnectionStatus == OTSessionConnectionStatusConnected { print("disconnecting....") session.disconnect(nil) dismiss(animated: true) return } dismiss(animated: true) } // Converted to Swift 5.2 by Swiftify v5.2.26743 - https://swiftify.com/ //do { // print( // "subscriberDidConnectToStream (\(subscriber.stream.connection.connectionId))") // assert(subscriber == subscriber) // remoteVideo.addSubview(subscriber.view) // subscriber.view.frame = remoteVideo.bounds // // self.remoteVideo=_publisher.view; //} - do { print( "subscriber \(subscriber.stream.streamId) didFailWithError \(error)") } // Converted to Swift 5.2 by Swiftify v5.2.26743 - https://swiftify.com/ // MARK: - OTPublisher delegate callbacks func publisher( _ publisher: OTPublisherKit?, streamCreated stream: OTStream? ) { print("Publishing") } func publisher( _ publisher: OTPublisherKit?, streamDestroyed stream: OTStream? ) { if subscriber.stream.streamId == stream?.streamId { cleanupSubscriber() } cleanupPublisher() } // Converted to Swift 5.2 by Swiftify v5.2.26743 - https://swiftify.com/ func publisher( _ publisher: OTPublisherKit?, didFailWithError error: OTError? ) { if let error = error { print("publisher didFailWithError \(error)") } cleanupPublisher() } // MARK: - Ui Handel func hideVideoMuted() { remoteVideoMutedIndicator.hidden = true localVideoMutedBg.hidden = true localVideoMutedIndicator.hidden = true } func setupButtons() { perform(#selector(hideControlButtons), with: nil, afterDelay: 3) let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(remoteVideoTapped(_:))) view.addGestureRecognizer(tapGestureRecognizer) view.isUserInteractionEnabled = true } // Converted to Swift 5.2 by Swiftify v5.2.26743 - https://swiftify.com/ @objc func hideControlButtons() { controlButtons.hidden = true } func remoteVideoTapped(_ recognizer: UITapGestureRecognizer?) { if controlButtons.hidden { controlButtons.hidden = false perform(#selector(hideControlButtons), with: nil, afterDelay: 3) } } func resetHideButtonsTimer() { ClingoVideoCallViewController.cancelPreviousPerformRequests(withTarget: self) perform(#selector(hideControlButtons), with: nil, afterDelay: 3) } // Converted to Swift 5.2 by Swiftify v5.2.26743 - https://swiftify.com/ @IBAction func didClickMuteButton(_ sender: UIButton) { sender.isSelected = !sender.isSelected publisher.publishAudio = !sender.isSelected resetHideButtonsTimer() } @IBAction func didClickSpeakerButton(_ sender: UIButton) { sender.isSelected = !sender.isSelected subscriber.subscribeToAudio = !sender.isSelected resetHideButtonsTimer() } @IBAction func didClickVideoMuteButton(_ sender: UIButton) { sender.isSelected = !sender.isSelected if publisher.publishVideo { publisher.publishVideo = false } else { publisher.publishVideo = true } localVideo.hidden = sender.isSelected localVideoMutedBg.hidden = !sender.isSelected localVideoMutedIndicator.hidden = !sender.isSelected resetHideButtonsTimer() } // Converted to Swift 5.2 by Swiftify v5.2.26743 - https://swiftify.com/ @IBAction func didClickSwitchCameraButton(_ sender: UIButton) { sender.isSelected = !sender.isSelected if sender.isSelected { publisher.cameraPosition = RPCameraPosition(rawValue: AVCaptureDevice.Position.back.rawValue) } else { publisher.cameraPosition = RPCameraPosition(rawValue: AVCaptureDevice.Position.front.rawValue) } resetHideButtonsTimer() } @IBAction func hangUp(_ sender: UIButton) { sessionDisconnect() } // Converted to Swift 5.2 by Swiftify v5.2.26743 - https://swiftify.com/ func startTimer(_ callDuration: String?, _ warningTime: String?) { } func -currentTime as? Date! do { let startCallTime = Date() dateFormatter.dateFormat = "yyyyMMddHHmmss" let resultString = dateFormatter.string(from: startCallTime) let date = dateFormatter.date(from: resultString) return date } }