// // JuPhoonCallViewController.m // watch // // Created by Apple on 2019/4/29. // Copyright © 2019年 xTT. All rights reserved. // //ios 4~10 #import #import //ios > 10 remove by lsz 2020-12-22 //#import //#import #import "JuPhoonCallViewController.h" //#import "User.h" //#import "Device.h" #import "JCManager.h" #import #import "AppDelegate.h" /*CXCallObserverDelegate*/ @interface JuPhoonCallViewController () { AVAudioPlayer *audioPlayer; int wait_duration; NSInteger tempElapsed ; BOOL hangUping; CTCallCenter *callCenter_old; //CXCallObserver *callObserver; } /** 控制 挂断 和 接听的 容器 */ @property (weak, nonatomic) IBOutlet UIStackView *buttonStackView; /** 主动挂断按钮 View */ @property (weak, nonatomic) IBOutlet UIView *activeHangupView; /** 右侧按钮的 容器 View */ @property (weak, nonatomic) IBOutlet UIView *rightBtnView; /// 转换摄像头(视频) 免提 (语音) @property (weak, nonatomic) IBOutlet UILabel *rightBtnDesLabel; /// 转换摄像头的图像按钮(视频) 免提的图像按钮 (语音) @property (weak, nonatomic) IBOutlet UIButton *rightBtn; /** 静音按钮 容器View */ @property (weak, nonatomic) IBOutlet UIView *muteBtnView; /** 被动挂断按钮 View */ @property (weak, nonatomic) IBOutlet UIView *hangupView; /** 接听按钮 View */ @property (weak, nonatomic) IBOutlet UIView *acceptView; @property (strong, nonatomic) NSTimer *callDurationTimer; @property (weak, nonatomic) IBOutlet UILabel *timeLabel; /** 是否是接通状态 */ @property (nonatomic) BOOL isCall; @property (weak, nonatomic) IBOutlet UIImageView *headImageView; @property (weak, nonatomic) IBOutlet UILabel *nameLabel; @property (weak, nonatomic) IBOutlet UIView *backView; /// 是否未打开麦克风 @property (nonatomic) BOOL isUNAuthorizationTypeAudio; /// 是否未打开相机 @property (nonatomic) BOOL isUNAuthorizationTypeCamera; @end @implementation JuPhoonCallViewController -(BOOL)shouldAutorotate{ return NO; } - (void)judgeAuthorization{ if(self.isUNAuthorizationTypeCamera == YES){ [self showAlertAuthorizationTypeCamera]; if(self.isReceiveCall){ [self activeHangUpBtnAction:nil]; }else{ [self hangUpButton:nil]; } }else if(self.isUNAuthorizationTypeAudio == YES){ [self showAlertAuthorizationTypeVideo]; if(self.isReceiveCall){ [self activeHangUpBtnAction:nil]; }else{ [self hangUpButton:nil]; } } } - (void)viewDidLoad { [super viewDidLoad]; kWeakSelf(self) if ([UIApplication sharedApplication].applicationState != UIApplicationStateActive){ //当处于非前台时 [[NSNotificationCenter defaultCenter] addObserverForName:UIApplicationDidBecomeActiveNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification * _Nonnull note) { //当从后台变为前台时收到的通知 [weakself judgeAuthorization]; }]; } JLAuthorizationManager *jlManager = [JLAuthorizationManager defaultManager]; [jlManager JL_requestAuthorizationWithAuthorizationType:JLAuthorizationTypeMicrophone authorizedHandler:nil unAuthorizedHandler:^{ weakself.isUNAuthorizationTypeAudio = YES; }]; [jlManager JL_requestAuthorizationWithAuthorizationType:JLAuthorizationTypeCamera authorizedHandler:nil unAuthorizedHandler:^{ weakself.isUNAuthorizationTypeCamera = YES; }]; // MARK: 处理来电接听挂断 if([UIDevice currentDevice].systemVersion.floatValue > 10.0){ //callObserver= [CXCallObserver new]; //[callObserver setDelegate:self queue:dispatch_get_main_queue()]; }else{ callCenter_old= [CTCallCenter new]; callCenter_old.callEventHandler = ^(CTCall *call) { dispatch_async(dispatch_get_main_queue(), ^{ if ([call.callState isEqualToString:CTCallStateDialing]) { NSLog(@"电话主动拨打电话"); } else if ([call.callState isEqualToString:CTCallStateConnected]) { NSLog(@"电话接通"); [weakself activeHangUpBtnAction:nil]; } else if ([call.callState isEqualToString:CTCallStateDisconnected]) { NSLog(@"电话挂断"); } else if ([call.callState isEqualToString:CTCallStateIncoming]) { NSLog(@"电话被叫"); } else { NSLog(@"电话其他状态"); } }); }; } [self initUI]; //订阅状态接收的通知 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(updateUI:) name:kCallNotification object:nil]; self.statusLabel.text = GJText(@"正在发起通话请求..."); self.jietingLabel.text = GJText(@"接听"); self.guanduanLabel.text = GJText(@"挂断"); self.guanduanLabel1.text = GJText(@"挂断"); self.jingyinLabel.text = GJText(@"静音"); } -(void)showAlertAuthorizationTypeVideo { EasyAlertView *alertV = [EasyAlertView alertViewWithTitle:GJText(@"请在iPhone的\"设置-隐私-麦克风\"选项中,允许守护星访问你的麦克风") subtitle:nil AlertViewType:AlertViewTypeSystemAlert config:nil]; [alertV addAlertItem:^EasyAlertItem *{ return [EasyAlertItem itemWithTitle:GJText(@"确定") type:AlertItemTypeSystemDefault callback:^(EasyAlertView *showview, long index) { //[[UIApplication sharedApplication] openURL:[NSURL URLWithString:UIApplicationOpenSettingsURLString]]; }]; }]; [alertV showAlertView]; } - (void)showAlertAuthorizationTypeCamera { EasyAlertView *alertV = [EasyAlertView alertViewWithTitle:GJText(@"在iPhone的\"设置-隐私-相机\"选项中,允许守护星访问你的相机") subtitle:nil AlertViewType:AlertViewTypeSystemAlert config:nil]; [alertV addAlertItem:^EasyAlertItem *{ return [EasyAlertItem itemWithTitle:GJText(@"确定") type:AlertItemTypeSystemDefault callback:^(EasyAlertView *showview, long index) { //[[UIApplication sharedApplication] openURL:[NSURL URLWithString:UIApplicationOpenSettingsURLString]]; }]; }]; [alertV showAlertView]; } #pragma mark ---- CXCallObserverDelegate---- //- (void)callObserver:(CXCallObserver *)callObserver callChanged:(CXCall *)call{ // NSLog(@"outgoing :%d onHold :%d hasConnected :%d hasEnded :%d",call.outgoing,call.onHold,call.hasConnected,call.hasEnded); /* 拨打: outgoing :1 onHold :0 hasConnected :0 hasEnded :0 拒绝: outgoing :1 onHold :0 hasConnected :0 hasEnded :1 链接: outgoing :1 onHold :0 hasConnected :1 hasEnded :0 挂断: outgoing :1 onHold :0 hasConnected :1 hasEnded :1 对方未接听时挂断: outgoing :1 onHold :0 hasConnected :0 hasEnded :1 新来电话: outgoing :0 onHold :0 hasConnected :0 hasEnded :0 保留并接听: outgoing :1 onHold :1 hasConnected :1 hasEnded :0 另一个挂掉: outgoing :0 onHold :0 hasConnected :1 hasEnded :0 保持链接: outgoing :1 onHold :0 hasConnected :1 hasEnded :1 对方挂掉: outgoing :0 onHold :0 hasConnected :1 hasEnded :1 */ //接通 另一个挂掉 //if (!call.outgoing && !call.onHold && call.hasConnected && !call.hasEnded) { // [self activeHangUpBtnAction:nil]; //} //} - (void)viewWillAppear:(BOOL)animated { [super viewWillAppear:animated]; //强制亮屏 [[UIApplication sharedApplication] setIdleTimerDisabled:YES]; if ([UIApplication sharedApplication].applicationState == UIApplicationStateActive){ [self judgeAuthorization]; } } - (void)viewWillDisappear:(BOOL)animated { [super viewWillDisappear:animated]; //取消强制亮屏 [[UIApplication sharedApplication] setIdleTimerDisabled:NO]; [self stopRing]; [self _stopCallDurationTimer]; self.nameLabel.text = nil; self.timeLabel.text = nil; //if(callObserver){ // [callObserver setDelegate:nil queue:dispatch_get_main_queue()]; // callObserver = nil; //} if(callCenter_old){ [callCenter_old setCallEventHandler:nil]; callCenter_old = nil; } // [[JCManager shared].client logout]; } -(void)initUI{ //等待时的图片 //判断性别 NSString *sexImageName; if(self.device.sex == 0) { //女 sexImageName = @"icon_girl_head_portrait"; } else { //男 sexImageName = @"icon_boy_head_portrait"; } [self.headImageView sd_setImageWithURL:[NSURL URLWithString:self.device.image] placeholderImage:ImageName_(sexImageName) options:SDWebImageRetryFailed]; self.nameLabel.text = self.device.name; self.timeLabel.hidden = YES; //self.statusLabel.hidden = YES; NSString * music = @"ring"; if(self.isReceiveCall){ //呼入 music = @"ring"; //隐藏 主动挂断按钮 self.activeHangupView.hidden = YES; self.hangupView.hidden = NO; self.acceptView.hidden = NO; }else{ //呼出 music = @"tones"; //显示 主动挂断按钮 self.activeHangupView.hidden = NO; self.hangupView.hidden = YES; self.acceptView.hidden = YES; } //如果是在后台的情况,不响铃 if([UIApplication sharedApplication].applicationState != UIApplicationStateBackground){ dispatch_async(dispatch_get_main_queue(), ^{ [self playRing:music]; }); } self.muteBtnView.hidden = YES; self.rightBtnView.hidden = YES; } -(void)updateUI:(NSNotification *)noti{ //振铃 self.timeLabel.hidden = YES; JCCallItem *activeCall = [self getActiveCall]; if (activeCall.state == JCCallStatePending) { } else if (activeCall.state == JCCallStateTalking) { //通话中 [self stopRing]; [JCManager.shared.mediaDevice startAudio]; // NSLog(@"--------------------音频输出是否是扬声器 :JCManager.shared.mediaDevice.speakerOn : %d",JCManager.shared.mediaDevice.speakerOn) if(!self.callDurationTimer){ [self _startCallDurationTimer]; } self.timeLabel.hidden = NO; //self.statusLabel.hidden = YES; //显示主动挂断 self.activeHangupView.hidden = NO; //隐藏 接听和被动挂断 self.hangupView.hidden = YES; self.acceptView.hidden = YES; //显示 静音 self.muteBtnView.hidden = NO; if (activeCall.video) { self.nameLabel.hidden = YES; self.headImageView.hidden = YES; if (_localCanvas == nil && activeCall.uploadVideoStreamSelf) { [self openLocationCarmeraViewWithFullSScreen:NO]; //小屏 //本地 显示View 添加手势 [self addGestureRecognizer:_localCanvas.videoView]; //为远程View添加手势 [self addGestureRecognizer:_remoteCanvas.videoView]; } else if (_localCanvas != nil && !activeCall.uploadVideoStreamSelf) { [JCManager.shared.mediaDevice stopVideo:_localCanvas]; [_localCanvas.videoView removeFromSuperview]; _localCanvas = nil; } if (_remoteCanvas == nil && activeCall.uploadVideoStreamOther) { [self openRemoteCarmeraViewWithRenderId:activeCall.renderId isFull:YES]; //为远程View添加手势 [self addGestureRecognizer:_remoteCanvas.videoView]; //本地 显示View 添加手势 [self addGestureRecognizer:_localCanvas.videoView]; } else if (_remoteCanvas != nil && !activeCall.uploadVideoStreamOther) { [JCManager.shared.mediaDevice stopVideo:_remoteCanvas]; [_remoteCanvas.videoView removeFromSuperview]; _remoteCanvas = nil; } //视频默认 启用扬声器 if(!JCManager.shared.mediaDevice.isSpeakerOn){ [JCManager.shared.mediaDevice enableSpeaker:YES]; } [self.rightBtn setImage:[UIImage imageNamed:@"Button_Camera"] forState:0]; [self.rightBtn setImage:[UIImage imageNamed:@"Button_Camera_active"] forState:UIControlStateSelected]; self.rightBtnDesLabel.text = GJText(@"转换摄像头"); }else{ self.nameLabel.hidden = NO; self.headImageView.hidden = NO; //音频默认 不启用扬声器 [self.rightBtn setImage:[UIImage imageNamed:@"sound"] forState:0]; [self.rightBtn setImage:[UIImage imageNamed:@"sound_selected"] forState:UIControlStateSelected]; self.rightBtnDesLabel.text = GJText(@"免提"); } //摄像头转换(视频) 语音(免提) self.rightBtnView.hidden = NO; } else if(activeCall.state == JCCallStateOk || activeCall.state == JCCallStateCancel || activeCall.state == JCCallStateCanceled){ NSLog(@"状态改变: %ld",(long)activeCall.state); [UICommon MessageSuccessText:@"通话已结束"]; [JCManager.shared.mediaDevice stopAudio]; [JCManager.shared.mediaDevice stopCamera]; //通话正常结束 [self removeCanvas]; } } -(void)openLocationCarmeraViewWithFullSScreen:(BOOL)isFull { if(!_localCanvas){ NSLog(@"JCManager.shared.mediaDevice.camera : %@",JCManager.shared.mediaDevice.camera); _localCanvas = [JCManager.shared.mediaDevice startCameraVideo:JCMediaDeviceRenderFullScreen]; if(JCManager.shared.mediaDevice.camera.cameraType != JCMediaDeviceCameraTypeFront){ [JCManager.shared.mediaDevice switchCamera]; } [self.view insertSubview:_localCanvas.videoView aboveSubview:self.backView]; } if(isFull){ _localCanvas.videoView.frame = CGRectMake(0,0,SCREEN_WIDTH ,SCREEN_HEIGHT); }else{ _localCanvas.videoView.frame = CGRectMake(SCREEN_WIDTH*(1-0.25)-25, 50, SCREEN_WIDTH * 0.25, SCREEN_HEIGHT*0.25); } } -(void)openRemoteCarmeraViewWithRenderId:(NSString*)renderId isFull:(BOOL)isFull{ if(!_remoteCanvas){ _remoteCanvas = [JCManager.shared.mediaDevice startVideo:renderId renderType:JCMediaDeviceRenderFullContent]; // [_remoteCanvas rotate:0]; [self.view insertSubview:_remoteCanvas.videoView aboveSubview:self.backView]; } if(isFull){ _remoteCanvas.videoView.frame = CGRectMake(0,0,SCREEN_WIDTH ,SCREEN_HEIGHT); //需要把自己的换成小屏的 _localCanvas.videoView.frame = CGRectMake(SCREEN_WIDTH*(1-0.25)-25, 50, SCREEN_WIDTH * 0.25, SCREEN_HEIGHT*0.25); }else{ _remoteCanvas.videoView.frame = CGRectMake(SCREEN_WIDTH*(1-0.25)-25, 50, SCREEN_WIDTH * 0.25, SCREEN_HEIGHT*0.25); _localCanvas.videoView.frame = CGRectMake(0,0,SCREEN_WIDTH ,SCREEN_HEIGHT); } } -(void)removeCanvas { if (_localCanvas) { [JCManager.shared.mediaDevice stopVideo:_localCanvas]; [_localCanvas.videoView removeFromSuperview]; _localCanvas = nil; } if (_remoteCanvas) { [JCManager.shared.mediaDevice stopVideo:_remoteCanvas]; [_remoteCanvas.videoView removeFromSuperview]; _remoteCanvas = nil; } } //MARK: 为View 添加拖动和双击手势 -(void)addGestureRecognizer:(UIView*)view{ //添加拖动手势 UIPanGestureRecognizer *panGestureRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handlePan:)]; [view addGestureRecognizer:panGestureRecognizer]; //双击手势 UITapGestureRecognizer *doubleTapGesture = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(handleDoubleTap:)]; doubleTapGesture.numberOfTapsRequired =2; doubleTapGesture.numberOfTouchesRequired =1; [view addGestureRecognizer:doubleTapGesture]; } //MARK: --- 拖动手势 ---- - (void)handlePan:(UIPanGestureRecognizer*)recognizer{ UIView *selectView = recognizer.view; if(selectView.bounds.size.width != SCREEN_WIDTH){ //不是全屏状态 // Figure out where the user is trying to drag the view. CGPoint translation = [recognizer translationInView:self.view]; CGPoint newCenter = CGPointMake(recognizer.view.center.x+ translation.x, recognizer.view.center.y + translation.y);// 限制屏幕范围: newCenter.y = MAX(recognizer.view.frame.size.height/2, newCenter.y); newCenter.y = MIN(self.view.frame.size.height - recognizer.view.frame.size.height/2, newCenter.y); newCenter.x = MAX(recognizer.view.frame.size.width/2, newCenter.x); newCenter.x = MIN(self.view.frame.size.width - recognizer.view.frame.size.width/2,newCenter.x); recognizer.view.center = newCenter; [recognizer setTranslation:CGPointZero inView:self.view]; } } //MARK: --- 双击放大---- -(void)handleDoubleTap:(UIGestureRecognizer *)recognizer{ UIView *selectView = recognizer.view; CGRect tempRect = selectView.frame; if(selectView.bounds.size.width != SCREEN_WIDTH){ if([_localCanvas.videoView isEqual:selectView]){ _localCanvas.videoView.frame = CGRectMake(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT); _remoteCanvas.videoView.frame = tempRect; [self.view exchangeSubviewAtIndex:_remoteCanvas.videoView.getInSuperViewIndex withSubviewAtIndex:_localCanvas.videoView.getInSuperViewIndex]; }else{ _remoteCanvas.videoView.frame = CGRectMake(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT); _localCanvas.videoView.frame = tempRect; [self.view exchangeSubviewAtIndex:_localCanvas.videoView.getInSuperViewIndex withSubviewAtIndex:_remoteCanvas.videoView.getInSuperViewIndex]; } } } /** MARK: APP 主动挂断按钮 */ - (IBAction)activeHangUpBtnAction:(id)sender { [self stopRing]; [JCManager.shared.call term:[self getActiveCall] reason:JCCallReasonNone description:@"APP挂断"]; [JCManager.shared _stopCallTimeoutTimer]; [JCManager.shared _stopVideoLimitTimeoutTimer]; [JCManager.shared.mediaDevice stopVideo:_localCanvas]; [JCManager.shared.mediaDevice stopVideo:_remoteCanvas]; JCManager.shared.callViewController = nil; [self dismissViewControllerAnimated:YES completion:nil]; } /** MARK: APP 被动挂断按钮 */ - (IBAction)hangUpButton:(UIButton *)sender { [self stopRing]; [JCManager.shared.call term:[self getActiveCall] reason:JCCallReasonNone description:@"APP挂断"]; [JCManager.shared _stopCallTimeoutTimer]; [JCManager.shared _stopVideoLimitTimeoutTimer]; [JCManager.shared.mediaDevice stopVideo:_localCanvas]; JCManager.shared.callViewController = nil; [self dismissViewControllerAnimated:YES completion:nil]; } /** MARK: APP 接听按钮 */ - (IBAction)acceptBtnAction:(id)sender { [self stopRing]; self.statusLabel.text = @""; [[JCManager shared].call answer:[self getActiveCall] video:true]; } //MARK: 切换摄像头 / 切换免提 - (IBAction)didClickSwitchCameraButton:(UIButton *)sender { sender.selected = !sender.selected; if ([self.rightBtnDesLabel.text isEqualToString:GJText(@"免提")]) { // 切换免提 [JCManager.shared.mediaDevice enableSpeaker:sender.selected]; }else{ // 切换摄像头 [JCManager.shared.mediaDevice switchCamera]; } } //MARK: 静音 - (IBAction)didClickMuteButton:(UIButton *)sender { sender.selected = !sender.selected; //[JCManager.shared.call mute:[self getActiveCall]]; [JCManager.shared.call muteMicrophone:[self getActiveCall] mute:sender.selected]; } #pragma mark - 工具函数 -(JCCallItem*)getActiveCall { for (JCCallItem* item in JCManager.shared.call.callItems) { if (item.active) { return item; } } return nil; } - (NSString *)genCallInfo:(JCCallItem*)item { switch (item.state) { case JCCallStateInit: return GJText(@"呼叫中"); case JCCallStatePending: return GJText(@"振铃中"); case JCCallStateConnecting: return GJText(@"连接中"); case JCCallStateTalking: if (item.hold) { return GJText(@"挂起"); } else if (item.held) { return GJText(@"被挂起"); } else { return [self formatTalkingTime:((long)[[NSDate date] timeIntervalSince1970] - item.talkingBeginTime)]; } case JCCallStateOk: return GJText(@"通话结束"); case JCCallStateCancel: return GJText(@"通话结束"); case JCCallStateCanceled: return GJText(@"挂断"); case JCCallStateMissed: return GJText(@"未接"); default: return GJText(@"异常"); } } //- (NSString *)genNetStatus:(JCCallItem *)item { // if (item.state != JCCallStateTalking) { // return @""; // } // switch (item.netStatus) { // case JCCallNetWorkDisconnected: // return GJText(@"无网络"); // case JCCallNetWorkVeryBad: // return GJText(@"很差"); // case JCCallNetWorkBad: // return GJText(@"差"); // case JCCallNetWorkNormal: // return GJText(@"一般"); // case JCCallNetWorkGood: // return GJText(@"好"); // case JCCallNetWorkVeryGood: // return GJText(@"非常好"); // default: // return @""; // } //} //MARK: 响铃的 MP3 - (void)playRing:(NSString *)name { [self stopRing]; AVAudioSession *audioSession = [AVAudioSession sharedInstance]; [audioSession setCategory:AVAudioSessionCategoryPlayback error:nil]; [audioSession setActive:YES error:nil]; NSURL *path = [[NSBundle mainBundle] URLForResource:name withExtension:@"mp3"]; audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:path error:nil]; audioPlayer.numberOfLoops = -1; [audioPlayer play]; } - (void)stopRing { if (audioPlayer) { [audioPlayer stop]; audioPlayer = nil; } } #pragma mark - Timer - (void)_updateCallDuration { JCCallItem *item = [self getActiveCall]; if(item){ self.callDuration = [[NSDate date] timeIntervalSince1970] - item.talkingBeginTime; self.timeLabel.text = [self formatTalkingTime:((long)[[NSDate date] timeIntervalSince1970] - item.talkingBeginTime)]; } } - (NSString *)formatTalkingTime:(long)time { return [NSString stringWithFormat:@"%02ld:%02ld", time/60, time%60]; } - (void)_startCallDurationTimer { [self _stopCallDurationTimer]; self.callDuration = 0; self.callDurationTimer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(_updateCallDuration) userInfo:nil repeats:YES]; } - (void)_stopCallDurationTimer { if (self.callDurationTimer) { [self.callDurationTimer invalidate]; self.callDurationTimer = nil; } } @end