You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

667 lines
23 KiB

//
// JuPhoonCallViewController.m
// watch
//
// Created by Apple on 2019/4/29.
// Copyright © 2019xTT. All rights reserved.
//
//ios 4~10
#import <CoreTelephony/CTCallCenter.h>
#import <CoreTelephony/CTCall.h>
//ios > 10 remove by lsz 2020-12-22
//#import <CallKit/CXCallObserver.h>
//#import <CallKit/CXCall.h>
#import "JuPhoonCallViewController.h"
#import "User.h"
#import "Device.h"
#import "JCManager.h"
#import <JLAuthorizationManager.h>
#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];
WEAKSELF
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:JLAuthorizationTypeAudio
authorizedHandler:nil
unAuthorizedHandler:^{
weakSelf.isUNAuthorizationTypeAudio = YES;
}];
[jlManager JL_requestAuthorizationWithAuthorizationType:JLAuthorizationTypeVideo
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];
WEAKSELF
callCenter_old.callEventHandler = ^(CTCall *call) {
dispatch_async(dispatch_get_main_queue(), ^{
if ([call.callState isEqualToString:CTCallStateDialing]) {
xLog(@"电话主动拨打电话");
} else if ([call.callState isEqualToString:CTCallStateConnected]) {
xLog(@"电话接通");
[weakSelf activeHangUpBtnAction:nil];
} else if ([call.callState isEqualToString:CTCallStateDisconnected]) {
xLog(@"电话挂断");
} else if ([call.callState isEqualToString:CTCallStateIncoming]) {
xLog(@"电话被叫");
} else {
xLog(@"电话其他状态");
}
});
};
}
[self initUI];
//订阅状态接收的通知
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(updateUI:) name:kCallNotification object:nil];
}
-(void)showAlertAuthorizationTypeVideo{
LGAlertView *alertView = [[LGAlertView alloc] initWithTitle:[NSString stringWithFormat:@"请在iPhone的\"设置-隐私-麦克风\"选项中,允许%@访问你的麦克风",APPName] message:nil style:LGAlertViewStyleAlert buttonTitles:@[@"确定"] cancelButtonTitle:@"" destructiveButtonTitle:nil actionHandler:^(LGAlertView *alertView, NSString *title, NSUInteger index) {
//[[UIApplication sharedApplication] openURL:[NSURL URLWithString:UIApplicationOpenSettingsURLString]];
} cancelHandler:^(LGAlertView *alertView) {
} destructiveHandler:nil];
[alertView showAnimated:YES completionHandler:nil];
}
-(void)showAlertAuthorizationTypeCamera{
LGAlertView *alertView = [[LGAlertView alloc] initWithTitle:[NSString stringWithFormat:@"请在iPhone的\"设置-隐私-相机\"选项中,允许%@访问你的相机",APPName] message:nil style:LGAlertViewStyleAlert buttonTitles:@[@"确定"] cancelButtonTitle:@"" destructiveButtonTitle:nil actionHandler:^(LGAlertView *alertView, NSString *title, NSUInteger index) {
} cancelHandler:^(LGAlertView *alertView) {
} destructiveHandler:nil];
[alertView showAnimated:YES completionHandler:nil];
}
#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([cUser.cDevice.sex isEqualToString:@"girl"]){
//
sexImageName = @"icon_girl_head_portrait";
}else{
//
sexImageName = @"icon_boy_head_portrait";
}
[self.headImageView sd_setImageWithURL:[NSURL URLWithString:self.device.avator]
placeholderImage:[myHelper getImageWithName: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];
// xLog(@"--------------------音频输出是否是扬声器 :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 = @"转换摄像头";
}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 = @"免提";
}
//摄像头转换(视频) 语音(免提)
self.rightBtnView.hidden = NO;
} else if(activeCall.state == JCCallStateOk ||
activeCall.state == JCCallStateCancel ||
activeCall.state == JCCallStateCanceled){
xLog(@"状态改变: %ld",(long)activeCall.state);
[UICommon MessageSuccessText:@"通话已结束" isImg:NO];
[JCManager.shared.mediaDevice stopAudio];
[JCManager.shared.mediaDevice stopCamera];
//通话正常结束
[self removeCanvas];
}
}
-(void)openLocationCarmeraViewWithFullSScreen:(BOOL)isFull{
if(!_localCanvas){
xLog(@"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,ScreenWidth ,ScreenHeight);
}else{
_localCanvas.videoView.frame = CGRectMake(ScreenWidth*(1-0.25)-25, 50, ScreenWidth * 0.25, ScreenHeight*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,ScreenWidth ,ScreenHeight);
//需要把自己的换成小屏的
_localCanvas.videoView.frame = CGRectMake(ScreenWidth*(1-0.25)-25, 50, ScreenWidth * 0.25, ScreenHeight*0.25);
}else{
_remoteCanvas.videoView.frame = CGRectMake(ScreenWidth*(1-0.25)-25, 50, ScreenWidth * 0.25, ScreenHeight*0.25);
_localCanvas.videoView.frame = CGRectMake(0,0,ScreenWidth ,ScreenHeight);
}
}
-(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 != ScreenWidth){ //不是全屏状态
// 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 != ScreenWidth){
if([_localCanvas.videoView isEqual:selectView]){
_localCanvas.videoView.frame = CGRectMake(0, 0, ScreenWidth, ScreenHeight);
_remoteCanvas.videoView.frame = tempRect;
[self.view exchangeSubviewAtIndex:_remoteCanvas.videoView.getInSuperViewIndex withSubviewAtIndex:_localCanvas.videoView.getInSuperViewIndex];
}else{
_remoteCanvas.videoView.frame = CGRectMake(0, 0, ScreenWidth, ScreenHeight);
_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];
[[JCManager shared].call answer:[self getActiveCall] video:true];
}
//MARK: 切换摄像头 / 切换免提
- (IBAction)didClickSwitchCameraButton:(UIButton *)sender {
sender.selected = !sender.selected;
if ([self.rightBtnDesLabel.text isEqualToString:@"免提"]) {
// 切换免提
[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 @"呼叫中";
case JCCallStatePending:
return @"振铃中";
case JCCallStateConnecting:
return @"连接中";
case JCCallStateTalking:
if (item.hold) {
return @"挂起";
} else if (item.held) {
return @"被挂起";
} else {
return [self formatTalkingTime:((long)[[NSDate date] timeIntervalSince1970] - item.talkingBeginTime)];
}
case JCCallStateOk:
return @"通话结束";
case JCCallStateCancel:
return @"通话结束";
case JCCallStateCanceled:
return @"挂断";
case JCCallStateMissed:
return @"未接";
default:
return @"异常";
}
}
//- (NSString *)genNetStatus:(JCCallItem *)item {
// if (item.state != JCCallStateTalking) {
// return @"";
// }
// switch (item.netStatus) {
// case JCCallNetWorkDisconnected:
// return @"无网络";
// case JCCallNetWorkVeryBad:
// return @"很差";
// case JCCallNetWorkBad:
// return @"差";
// case JCCallNetWorkNormal:
// return @"一般";
// case JCCallNetWorkGood:
// return @"好";
// case JCCallNetWorkVeryGood:
// return @"非常好";
// 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