You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
447 lines
13 KiB
Swift
447 lines
13 KiB
Swift
//
|
|
// 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
|
|
}
|
|
|
|
|
|
}
|