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.
doctor_app_flutter/ios/Runner/VideoCallViewController.swift

504 lines
16 KiB
Swift

//
// ViewController.swift
// Runner
//
// Created by Mohammad Aljammal & Elham Rababah on 23/6/20.
// Copyright © 2020 The Chromium Authors. All rights reserved.
//
import UIKit
import OpenTok
import Alamofire
import AADraggableView
class VideoCallViewController: UIViewController {
var session: OTSession?
var publisher: OTPublisher?
var subscriber: OTSubscriber?
var kApiKey:String = ""
var kSessionId:String = ""
var kToken:String = ""
var VC_ID: Int = 0
var TokenID: String = ""
var generalid : String = ""
var DoctorId: Int = 0
var baseUrl:String = ""
var callBack: ICallProtocol?
var timer = Timer()
var seconds = 30
var isUserConnect : Bool = false
var onMinimize:((Bool)->Void)? = nil
var onHide:(()->Void)? = nil
var onVideoDuration:((String)->Void)? = nil
var onClose:(()->Void)? = nil
@IBOutlet weak var lblRemoteUsername: UILabel!
// Bottom Actions
@IBOutlet weak var videoMuteBtn: UIButton!
@IBOutlet weak var micMuteBtn: UIButton!
@IBOutlet weak var camSwitchBtn: UIButton!
@IBOutlet var minimizeConstraint: [NSLayoutConstraint]!
@IBOutlet var maximisedConstraint: [NSLayoutConstraint]!
@IBOutlet weak var hideVideoBtn: UIButton!
@IBOutlet weak var draggableBoundryDefiner: UIView!
var localVideoDraggable:AADraggableView?
@IBOutlet weak var controlButtons: UIView!
@IBOutlet weak var remoteVideoMutedIndicator: UIImageView!
@IBOutlet weak var localVideoMutedBg: UIView!
@IBOutlet weak var lblCallDuration: UILabel!
@IBOutlet weak var remoteVideo: UIView!
@IBOutlet weak var localVideo: UIView!{
didSet{
localVideoDraggable = localVideo?.superview as? AADraggableView
localVideoDraggable?.reposition = .edgesOnly
}
}
override func viewDidLoad() {
super.viewDidLoad()
localVideoDraggable?.respectedView = draggableBoundryDefiner
}
@IBAction func didClickMuteButton(_ sender: UIButton) {
sender.isSelected = !sender.isSelected
publisher!.publishAudio = !sender.isSelected
}
@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.isHidden = sender.isSelected
localVideoMutedBg.isHidden = !sender.isSelected
// resetHideButtonsTimer()
}
@IBAction func didClickSwitchCameraButton(_ sender: UIButton) {
sender.isSelected = !sender.isSelected
if sender.isSelected {
publisher!.cameraPosition = AVCaptureDevice.Position.front
} else {
publisher!.cameraPosition = AVCaptureDevice.Position.back
}
/// resetHideButtonsTimer()
}
@IBAction func hangUp(_ sender: UIButton) {
callBack?.sessionDone(res:["callResponse":"CallEnd"])
sessionDisconnect()
}
@IBAction func hideVideoBtnTapped(_ sender: Any) {
onHide?()
}
var minimized = false
@IBAction func onMinimize(_ sender: UIButton) {
minimized = !minimized
onMinimize?(minimized)
sender.isSelected = minimized
NSLayoutConstraint.activate(minimized ? minimizeConstraint : maximisedConstraint)
NSLayoutConstraint.deactivate(minimized ? maximisedConstraint : minimizeConstraint)
localVideoDraggable?.enable(!minimized)
lblRemoteUsername.isHidden = minimized
hideVideoBtn.isHidden = !minimized
lblCallDuration.superview?.isHidden = !hideVideoBtn.isHidden
let min_ = minimized
UIView.animate(withDuration: 0.5) {
self.videoMuteBtn.isHidden = min_
self.micMuteBtn.isHidden = min_
self.camSwitchBtn.isHidden = min_
let localVdoSize = self.localVideo.bounds.size
let remoteVdoSize = self.remoteVideo.bounds.size
self.publisher?.view?.frame = CGRect(x: 0, y: 0, width: localVdoSize.width, height: localVdoSize.height)
self.subscriber?.view?.frame = CGRect(x: 0, y: 0, width: remoteVdoSize.width, height: remoteVdoSize.height)
self.publisher?.view?.layoutIfNeeded()
self.subscriber?.view?.layoutIfNeeded()
}
}
var durationTimer:Timer?;
func startUpdateCallDuration(){
var seconds = 0
durationTimer = Timer.scheduledTimer(withTimeInterval: 1, repeats: true) { timer in
seconds = seconds+1
let durationSegments = (seconds / 3600, (seconds % 3600) / 60, (seconds % 3600) % 60)
let hours = String(format: "%02d", durationSegments.0)
let mins = String(format: "%02d", durationSegments.1)
let secs = String(format: "%02d", durationSegments.2)
let durationString = "\(mins):\(secs)"
self.lblCallDuration.text = durationString
self.onVideoDuration?(durationString)
}
}
func start(params:VideoCallRequestParameters){
self.kApiKey = params.apiKey ?? ""
self.kSessionId = params.sessionId ?? ""
self.kToken = params.token ?? ""
self.VC_ID = params.vcId ?? 0
self.generalid = params.generalId ?? ""
self.TokenID = params.tokenId ?? ""
self.DoctorId = params.doctorId ?? 0
self.baseUrl = params.baseUrl ?? ""
setupButtons()
askForMicrophonePermission()
requestCameraPermissionsIfNeeded()
hideVideoMuted()
setupSession()
}
private func changeCallStatus(callStatus:Int){
let URL_USER_REGISTER = baseUrl+"LiveCareApi/DoctorApp/ChangeCallStatus"
let headers: HTTPHeaders = ["Content-Type":"application/json","Accept":"application/json",]
let parameters = [
"CallStatus":callStatus,
"VC_ID": VC_ID,
"TokenID": TokenID,
"generalid": generalid,
"DoctorId" : DoctorId ,
] as [String : Any]
AF.request(URL_USER_REGISTER, method: .post,parameters: parameters, encoding: JSONEncoding.default, headers: headers).responseJSON{
response in
if let result = response.value {
let jsonData = result as! NSObject
let resultVal = jsonData.value(forKey: "Result")
print(resultVal as Any)
}
}
}
private func getSessionStatus() {
let URL_USER_REGISTER = baseUrl+"LiveCareApi/DoctorApp/GetSessionStatus"
let headers: HTTPHeaders = [
"Content-Type":"application/json",
"Accept":"application/json",
]
let parameters = [
"VC_ID": VC_ID,
"TokenID": TokenID,
"generalid": generalid,
"DoctorId" : DoctorId ,
] as [String : Any]
AF.request(URL_USER_REGISTER, method: .post,parameters: parameters, encoding: JSONEncoding.default, headers: headers).responseJSON{
response in
if self.isUserConnect {
} else {
if let result = response.value {
let jsonData = result as! NSObject
if((jsonData.value(forKey: "SessionStatus")) as! Int == 2 || (jsonData.value(forKey: "SessionStatus")) as! Int == 3) {
//jsonData
let jsonObject: [String: Any] = [
"sessionStatus": result ,
"callResponse": "CallNotRespond",
]
self.callBack?.sessionNotResponded(res: jsonObject)
}
}
self.sessionDisconnect();
self.timer.invalidate()
}
}
}
func setupButtons() {
perform(#selector(hideControlButtons), with: nil, afterDelay: 3)
let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(remoteVideoTapped(_:)))
view.addGestureRecognizer(tapGestureRecognizer)
view.isUserInteractionEnabled = true
}
// MARK: -Microphone Camera and Permission Request
func askForMicrophonePermission() {
switch AVAudioSession.sharedInstance().recordPermission {
case AVAudioSession.RecordPermission.granted:
break
case AVAudioSession.RecordPermission.denied:
break
case AVAudioSession.RecordPermission.undetermined:
// 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
}
}
func notifyUserOfCameraAccessDenial() {
// display a useful message asking the user to grant permissions from within Settings > Privacy > Camera
}
func sessionDisconnect() {
changeCallStatus(callStatus: 16)
if (session != nil) {
print("disconnecting....")
session!.disconnect(nil)
dismiss(animated: true)
}
dismiss(animated: true)
onClose?()
}
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 hideVideoMuted() {
remoteVideoMutedIndicator.isHidden = true
localVideoMutedBg.isHidden = true
}
func setupSession() {
//setup one time session
if (session != nil) {
session = nil
}
session = OTSession(
apiKey: kApiKey,
sessionId: kSessionId,
delegate: self)
var error: OTError?
session!.connect(withToken: kToken,error: &error)
}
func connectToAnOpenTokSession() {
session = OTSession(apiKey: kApiKey, sessionId: kSessionId, delegate: self)
var error: OTError?
session?.connect(withToken: kToken, error: &error)
if error != nil {
print(error!)
}
}
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)
})
}
@objc func updateTimer(){
seconds -= 1 //This will decrement(count down)the seconds.
print(seconds)
if seconds == 0 {
getSessionStatus()
}
}
}
extension VideoCallViewController: OTSessionDelegate {
func sessionDidConnect(_ session: OTSession) {
print("The client connected to the OpenTok session.")
timer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: (#selector(VideoCallViewController.updateTimer)), userInfo: nil, repeats: true)
setupPublisher()
}
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)
}
publisher?.view!.frame = CGRect(x: 0, y: 0, width: localVideo.bounds.size.width, height: localVideo.bounds.size.height)
publisher?.view?.layer.cornerRadius = 5
publisher?.view?.clipsToBounds = true
localVideo.addSubview((publisher?.view)!)
}
func sessionDidDisconnect(_ session: OTSession) {
print("The client disconnected from the OpenTok session.")
}
func session(_ session: OTSession, didFailWithError error: OTError) {
changeCallStatus(callStatus: 16)
print("The client failed to connect to the OpenTok session: \(error).")
}
func session(
_ session: OTSession,
connectionDestroyed connection: OTConnection
) {
if subscriber?.stream!.connection.connectionId == connection.connectionId {
cleanupSubscriber()
}
sessionDisconnect()
}
func session(_ session: OTSession, streamCreated stream: OTStream) {
subscriber = OTSubscriber(stream: stream, delegate: self)
guard let subscriber = subscriber else {
return
}
var error: OTError?
session.subscribe(subscriber, error: &error)
guard error == nil else {
print(error!)
return
}
guard let subscriberView = subscriber.view else {
return
}
subscriberView.frame = CGRect(x: 0, y: 0, width: remoteVideo.bounds.width, height: remoteVideo.bounds.height)
remoteVideo.addSubview(subscriberView)
startUpdateCallDuration()
}
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)
}
}
func session(_ session: OTSession, streamDestroyed stream: OTStream) {
if subscriber?.stream?.streamId == stream.streamId {
cleanupSubscriber()
}
print("A stream was destroyed in the session.")
}
func cleanupSubscriber() {
subscriber?.view!.removeFromSuperview()
subscriber = nil
}
func session(
_ session: OTSession?,
connectionCreated connection: OTConnection?
) {
// startTimer(callDuration, warningDuration)
if let connectionId = connection?.connectionId {
print("session connectionCreated (\(connectionId))")
}
changeCallStatus(callStatus: 3)
isUserConnect = true
timer.invalidate()
}
}
extension VideoCallViewController: OTPublisherDelegate {
func publisher(_ publisher: OTPublisherKit, didFailWithError error: OTError) {
print("The publisher failed: \(error)")
}
@objc func remoteVideoTapped(_ recognizer: UITapGestureRecognizer?) {
if controlButtons.isHidden {
controlButtons.isHidden = false
perform(#selector(hideControlButtons), with: nil, afterDelay: 3)
}
}
}
extension VideoCallViewController: OTSubscriberDelegate {
public func subscriberDidConnect(toStream subscriber: OTSubscriberKit) {
print("The subscriber did connect to the stream.")
}
public func subscriber(_ subscriber: OTSubscriberKit, didFailWithError error: OTError) {
print("The subscriber failed to connect to the stream.")
}
@objc func hideControlButtons() {
// controlButtons.isHidden = true
}
}