// // CallViewController.m // OpenDuo // // Created by suleyu on 2017/10/31. // Copyright © 2017 Agora. All rights reserved. // //ios > 10 //#import //#import #import "CallViewController.h" #import #import #import #import "MJExtension.h" #import "AppDelegate.h" //CXCallObserverDelegate @interface CallViewController () { AVAudioPlayer *audioPlayer; AgoraRtcEngineKit *mediaEngine; int wait_duration; NSInteger tempElapsed ; BOOL hangUping; //CXCallObserver *callObserver; } @property (strong, nonatomic) LGAlertView *alertView; /// 远端摄像头预览 @property (weak, nonatomic) IBOutlet UIView *remoteVideo; /// 自己摄像头预览 @property (weak, nonatomic) IBOutlet UIView *localVideo; ///头像 @property (weak, nonatomic) IBOutlet UIImageView *headImageView; /// 名称 @property (weak, nonatomic) UILabel *nameLabel; /// 通话时间 @property (weak, nonatomic) UILabel *timeLabel; /// 摄像头开关 @property (weak, nonatomic) UIButton *onSwitchCameraBtn; /// 摄像头切换 @property (weak, nonatomic) UIButton *switchCameraBtn; /// 静音按钮 @property (weak, nonatomic) UIButton *muteBtn; /// 接听按钮 @property (nonatomic ,weak) UIButton *answerBtn; /// 挂断按钮(接通之后或拨打等待接听) @property (nonatomic ,weak) UIButton *hangUpBtn; /// 挂断按钮(被动呼叫等待接听) @property (nonatomic ,weak) UIButton *lefthangUpBtn; /// 麦克风开关 @property (nonatomic ,weak) UIButton *microphoneBtn; /// 呼叫状态 @property (nonatomic ,weak) UILabel *statusLabel; /// 与谁的通话 @property (nonatomic ,weak) UILabel *tonghuaLabel; @property (strong, nonatomic) AgoraRtcEngineKit *agoraKit; @property (nonatomic) int timeLength; @property (strong, nonatomic) NSTimer *timeTimer; /** 是否是接通状态 */ @property (nonatomic) BOOL isCall; @end @implementation CallViewController - (void)subViewsLayout { CGSize btnSize = CGSizeMake(70, 100); WEAKSELF /// 摄像头切换 UIButton *switchCameraBtn = [UICommon ui_buttonSimple:CGRectZero font:Font_(0) normalColor:KKClearColor normalText:@"" click:^(id x) { [weakSelf.agoraKit switchCamera]; }]; switchCameraBtn.hidden = YES; [switchCameraBtn setImage:ImageName_(@"video_icon_camera") forState:0]; self.switchCameraBtn = switchCameraBtn; [self.view addSubview:switchCameraBtn]; [switchCameraBtn mas_makeConstraints:^(MASConstraintMaker *make) { make.right.equalTo(self.view.mas_right).inset(16); make.top.equalTo(self.view).offset(52); make.size.mas_equalTo(CGSizeMake(28, 28)); }]; self.remoteVideo.frame = CGRectMake(0, 0, ScreenWidth, ScreenHeight); /// 自己摄像头预览 self.localVideo.frame = CGRectMake(ScreenWidth-116, 104, 100, 130); self.localVideo.layer.borderWidth = 1; self.localVideo.layer.borderColor = KKWhiteColorColor.CGColor; self.localVideo.layer.cornerRadius = 4; self.localVideo.layer.masksToBounds = YES; self.localVideo.hidden = YES; self.headImageView.hidden = YES; self.headImageView.layer.cornerRadius = 12; self.headImageView.layer.masksToBounds = YES; [self.headImageView mas_makeConstraints:^(MASConstraintMaker *make) { make.centerX.equalTo(self.view); make.top.equalTo(self.view).offset(154); make.size.mas_equalTo(CGSizeMake(128, 128)); }]; UILabel *nameLabel = [UICommon ui_label:CGRectZero lines:0 align:NSTextAlignmentCenter font:FontBold_(24) textColor:KKWhiteColorColor text:@"" Radius:0]; nameLabel.hidden = YES; self.nameLabel = nameLabel; [self.view addSubview:nameLabel]; [nameLabel mas_makeConstraints:^(MASConstraintMaker *make) { make.centerX.equalTo(self.view); make.top.equalTo(self.headImageView.mas_bottom).offset(14); }]; /// 挂断按钮 UIButton *hangUpBtn = [UICommon ui_buttonSimple:CGRectZero font:Font_(14) normalColor:KKWhiteColorColor normalText:@"挂断" click:^(UIButton *btn) { [weakSelf activeHangUpBtnAction:btn]; }]; hangUpBtn.size = btnSize; hangUpBtn.hidden = YES; [hangUpBtn setImage:ImageName_(@"video_icon_cancle") forState:0]; [self setBtnImageAndTitle:hangUpBtn]; self.hangUpBtn = hangUpBtn; [self.view addSubview:hangUpBtn]; [hangUpBtn mas_makeConstraints:^(MASConstraintMaker *make) { make.centerX.equalTo(self.view); make.bottom.equalTo(self.view.mas_bottom).inset(58); make.size.mas_equalTo(btnSize); }]; /// 摄像头开关 UIButton *onSwitchCameraBtn = [UICommon ui_buttonSimple:CGRectZero font:Font_(14) normalColor:KKWhiteColorColor normalText:@"" click:^(UIButton *btn) { btn.selected = !btn.selected; [weakSelf.agoraKit enableLocalVideo:!btn.selected]; }]; onSwitchCameraBtn.size = btnSize; onSwitchCameraBtn.hidden = YES; [onSwitchCameraBtn setImage:ImageName_(@"video_icon_ cameraono") forState:UIControlStateNormal]; [onSwitchCameraBtn setImage:ImageName_(@"video_icon_ cameraoff") forState:UIControlStateSelected]; [onSwitchCameraBtn setTitle:@"摄像头已开" forState:UIControlStateNormal]; [onSwitchCameraBtn setTitle:@"摄像头已关" forState:UIControlStateSelected]; [self setBtnImageAndTitle:onSwitchCameraBtn]; self.onSwitchCameraBtn = onSwitchCameraBtn; [self.view addSubview:onSwitchCameraBtn]; [onSwitchCameraBtn mas_makeConstraints:^(MASConstraintMaker *make) { make.right.equalTo(self.view.mas_right).inset(40); make.centerY.equalTo(hangUpBtn); make.size.mas_equalTo(btnSize); }]; /// 麦克风开关 UIButton *microphoneBtn = [UICommon ui_buttonSimple:CGRectZero font:Font_(14) normalColor:KKWhiteColorColor normalText:@"" click:^(UIButton *btn) { btn.selected = !btn.selected; [weakSelf.agoraKit muteLocalAudioStream:btn.selected]; }]; microphoneBtn.size = btnSize; microphoneBtn.hidden = YES; [microphoneBtn setImage:ImageName_(@"video_icon_muteon") forState:UIControlStateNormal]; [microphoneBtn setImage:ImageName_(@"video_icon_muteoff") forState:UIControlStateSelected]; [microphoneBtn setTitle:@"麦克风已开" forState:UIControlStateNormal]; [microphoneBtn setTitle:@"麦克风已关" forState:UIControlStateSelected]; [self setBtnImageAndTitle:microphoneBtn]; self.microphoneBtn = microphoneBtn; [self.view addSubview:microphoneBtn]; [microphoneBtn mas_makeConstraints:^(MASConstraintMaker *make) { make.left.equalTo(self.view).offset(40); make.centerY.equalTo(hangUpBtn); make.size.mas_equalTo(btnSize); }]; /// 挂断按钮(被动呼叫等待接听) UIButton *lefthangUpBtn = [UICommon ui_buttonSimple:CGRectZero font:Font_(14) normalColor:KKWhiteColorColor normalText:@"挂断" click:^(UIButton *btn) { [weakSelf hangUpButton:btn]; }]; lefthangUpBtn.size = btnSize; lefthangUpBtn.hidden = YES; [lefthangUpBtn setImage:ImageName_(@"video_icon_cancle") forState:0]; [self setBtnImageAndTitle:lefthangUpBtn]; self.lefthangUpBtn = lefthangUpBtn; [self.view addSubview:lefthangUpBtn]; [lefthangUpBtn mas_makeConstraints:^(MASConstraintMaker *make) { make.left.equalTo(self.view).offset(40); make.centerY.equalTo(hangUpBtn); make.size.mas_equalTo(btnSize); }]; /// 接听按钮 UIButton *answerBtn = [UICommon ui_buttonSimple:CGRectZero font:Font_(14) normalColor:KKWhiteColorColor normalText:@"接听" click:^(UIButton *btn) { [weakSelf acceptBtnAction:btn]; }]; answerBtn.size = btnSize; answerBtn.hidden = YES; [answerBtn setImage:ImageName_(@"video_icon_pickup") forState:UIControlStateNormal]; [self setBtnImageAndTitle:answerBtn]; self.answerBtn = answerBtn; [self.view addSubview:answerBtn]; [answerBtn mas_makeConstraints:^(MASConstraintMaker *make) { make.right.equalTo(self.view.mas_right).inset(40); make.centerY.equalTo(hangUpBtn); make.size.mas_equalTo(btnSize); }]; /// 通话时间 UILabel *timeLabel = [UICommon ui_label:CGRectZero lines:0 align:NSTextAlignmentCenter font:FontBold_(18) textColor:KKWhiteColorColor text:@"" Radius:0]; timeLabel.hidden = YES; self.timeLabel = timeLabel; [self.view addSubview:timeLabel]; [timeLabel mas_makeConstraints:^(MASConstraintMaker *make) { make.centerX.equalTo(self.view); make.bottom.equalTo(hangUpBtn.mas_top).inset(24); }]; UILabel *statusLabel = [UICommon ui_label:CGRectZero lines:0 align:NSTextAlignmentCenter font:Font_(16) textColor:KKWhiteColorColor text:@"" Radius:0]; statusLabel.hidden = YES; self.statusLabel = statusLabel; [self.view addSubview:statusLabel]; [statusLabel mas_makeConstraints:^(MASConstraintMaker *make) { make.centerX.equalTo(self.view); make.top.equalTo(nameLabel.mas_bottom).offset(60); }]; UILabel *tonghuaLabel = [UICommon ui_label:CGRectZero lines:0 align:NSTextAlignmentCenter font:FontBold_(18) textColor:KKWhiteColorColor text:@"" Radius:0]; tonghuaLabel.hidden = YES; self.tonghuaLabel = tonghuaLabel; [self.view addSubview:tonghuaLabel]; [tonghuaLabel mas_makeConstraints:^(MASConstraintMaker *make) { make.left.right.equalTo(self.view).inset(64); make.centerY.equalTo(switchCameraBtn); }]; } - (void)viewDidLoad { [super viewDidLoad]; WEAKSELF //添加通知 [[NSNotificationCenter defaultCenter] addObserverForName:AccountMessageNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification * _Nonnull note) { NSDictionary *dic = note.object; NSDictionary *msgDic = dic[@"message"]; NSString * msgType = msgDic[@"type"]; if([msgType isEqualToString:@"reject"]){ //拒绝视频通话 [weakSelf activeHangUpBtnAction:nil]; }else{ return ; } }]; [self subViewsLayout]; //view.layer.masksToBounds = YES; //判断性别 NSString *sexImageName = [cUser.cDevice.sex isEqualToString:@"girl"] ? @"icon_girl_head_portrait" : @"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 setupVideo]; //设置 本地视频摄像头 // [self setupLocalVideo]; JLAuthorizationManager *jlManager = [JLAuthorizationManager defaultManager]; [jlManager JL_requestAuthorizationWithAuthorizationType:JLAuthorizationTypeAudio authorizedHandler:nil unAuthorizedHandler:^{ LGAlertView *alertView = [[LGAlertView alloc] initWithTitle:@"请为作业帮打开麦克风权限" message:nil style:LGAlertViewStyleAlert buttonTitles:@[@"确定"] cancelButtonTitle:@"取消" destructiveButtonTitle:nil actionHandler:^(LGAlertView *alertView, NSString *title, NSUInteger index) { [[UIApplication sharedApplication] openURL:[NSURL URLWithString:UIApplicationOpenSettingsURLString]]; } cancelHandler:^(LGAlertView *alertView) { if(weakSelf.isReceiveCall){ [weakSelf activeHangUpBtnAction:nil]; }else{ [weakSelf hangUpButton:nil]; } } destructiveHandler:nil]; [alertView showAnimated:YES completionHandler:nil]; }]; // MARK: 处理来电接听挂断 if([UIDevice currentDevice].systemVersion.floatValue > 10.0){ //callObserver= [CXCallObserver new]; //[callObserver setDelegate:self queue:dispatch_get_main_queue()]; } } - (void)initializeAgoraEngine { xLog(@"声网 SDK 版本 %@",[AgoraRtcEngineKit getSdkVersion]); AgoraRtcEngineConfig *config = [AgoraRtcEngineConfig new]; config.appId = self.appid; config.areaCode = AgoraAreaCodeTypeCN; config.channelProfile = AgoraChannelProfileLiveBroadcasting; self.agoraKit = [AgoraRtcEngineKit sharedEngineWithConfig:config delegate:self]; //[self.agoraKit setChannelProfile:AgoraChannelProfileLiveBroadcasting]; [self.agoraKit setClientRole:AgoraClientRoleBroadcaster]; //[self.agoraKit setLogFile:@"agorasdk"]; /// 设置默认使用前置摄像头 AgoraCameraCapturerConfiguration *Camera = [[AgoraCameraCapturerConfiguration alloc] init]; Camera.cameraDirection = AgoraCameraDirectionFront; [self.agoraKit setCameraCapturerConfiguration:Camera]; [self.agoraKit enableVideo]; /// 设置 视频分辨率 [self setupVideo]; } /** 设置 视频分辨率 */ - (void)setupVideo { // Default mode is disableVideo [self.agoraKit setParameters:@"{\"engine.video.codec_type\":\"20\"}"]; [self.agoraKit setParameters:@"{\"rtc.audio.acm_ptime\":60}"]; [self.agoraKit setParameters:@"{\"che.audio.custom_payload_type\":9}"]; if(self.videoSize.width == 160 && self.videoSize.height == 128){ self.videoSize = CGSizeMake(160, 128); AgoraVideoEncoderConfiguration *encoderConfiguration = [[AgoraVideoEncoderConfiguration alloc] initWithSize:self.videoSize frameRate:5 bitrate:1000 orientationMode:AgoraVideoOutputOrientationModeFixedLandscape mirrorMode:AgoraVideoMirrorModeAuto]; encoderConfiguration.dimensions = self.videoSize; [self.agoraKit setVideoEncoderConfiguration:encoderConfiguration]; } else { //[self.agoraKit setParameters:@"{\"rtc.audio.custom_payload_type\":9}"]; self.videoSize = AgoraVideoDimension240x240; AgoraVideoEncoderConfiguration *encoderConfiguration = [[AgoraVideoEncoderConfiguration alloc] initWithSize:self.videoSize frameRate:5//AgoraVideoFrameRateFps7 bitrate:1000//AgoraVideoBitrateStandard orientationMode:AgoraVideoOutputOrientationModeFixedPortrait mirrorMode:AgoraVideoMirrorModeAuto]; encoderConfiguration.dimensions = AgoraVideoDimension240x240; [self.agoraKit setVideoEncoderConfiguration:encoderConfiguration]; } [self setupLocalVideo]; //添加拖动手势 UIPanGestureRecognizer *panGestureRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handlePan:)]; [self.remoteVideo addGestureRecognizer:panGestureRecognizer]; //双击手势 UITapGestureRecognizer *doubleTapGesture = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(handleDoubleTap:)]; doubleTapGesture.numberOfTapsRequired = 2; doubleTapGesture.numberOfTouchesRequired = 1; [self.remoteVideo addGestureRecognizer:doubleTapGesture]; } /** 初始化自己的 视频界面 */ - (void)setupLocalVideo { // if(self.videoSize.width == 160 && self.videoSize.height == 128) // self.localVideo.frame = CGRectMake(ScreenWidth-(128*Adapted(0.35))-50, 50, 160*Adapted(0.35), 128*Adapted(0.35)); // else // self.localVideo.frame = CGRectMake(ScreenWidth*(1-0.25)-25, 50, ScreenWidth * 0.25, ScreenHeight*0.25); self.localVideo.backgroundColor = UIColor.blackColor; AgoraRtcVideoCanvas *videoCanvas = [[AgoraRtcVideoCanvas alloc] init]; videoCanvas.uid = self.uid; videoCanvas.view = self.localVideo; //videoCanvas.renderMode = AgoraVideoRenderModeFit; videoCanvas.mirrorMode = AgoraVideoMirrorModeAuto; [self.agoraKit setupLocalVideo:videoCanvas]; [self.agoraKit startPreview]; [self.agoraKit setDefaultAudioRouteToSpeakerphone:YES]; //MARK: 设置录音的音量是原本的4倍 [self.agoraKit adjustRecordingSignalVolume:400]; self.localVideo.hidden = YES; //添加拖动手势 UIPanGestureRecognizer *panGestureRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handlePan:)]; [self.localVideo addGestureRecognizer:panGestureRecognizer]; //双击手势 UITapGestureRecognizer *doubleTapGesture = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(handleDoubleTap:)]; doubleTapGesture.numberOfTapsRequired = 2; doubleTapGesture.numberOfTouchesRequired = 1; [self.localVideo addGestureRecognizer:doubleTapGesture]; } /** MARK:加入通道 */ - (void)joinChannel { if(self.channelID && self.uid ) { WeakSelf AgoraRtcChannelMediaOptions *option = [AgoraRtcChannelMediaOptions new]; [option setPublishCameraTrack:YES]; [option setClientRoleType:AgoraClientRoleBroadcaster]; int res = [self.agoraKit joinChannelByToken:self.token channelId:self.channelID uid:self.uid mediaOptions:option joinSuccess:^(NSString * _Nonnull channel, NSUInteger uid, NSInteger elapsed) { xLog(@"加入通道"); //启动定时器 [weakSelf _startTimeTimer]; self.agoraKit.delegate = self; }]; xLog(@"加入通道res == %d" , res); //音频外放 [self.agoraKit setEnableSpeakerphone:YES]; //启用不自动锁屏 [UIApplication sharedApplication].idleTimerDisabled = YES; } } /** MARK: APP 接听按钮 */ - (IBAction)acceptBtnAction:(id)sender { self.isCall = YES; [self joinChannel]; [self stopRing]; } /** MARK: APP 主动挂断按钮 (接通后APP的挂断) */ - (void)activeHangUpBtnAction:(id)sender { [self stopRing]; [self leaveChannel]; if(!hangUping) { WEAKSELF if(sender){ //调 API 接口 下发指令给设备 上传 video_id [cUser activeHangUpVideoID:self.video_id WithDevice:self.device WithSuccess:^(id responseObject) { xLog(@"主动挂断成功"); self->hangUping = NO; [weakSelf dismissViewControllerAnimated:YES completion:nil]; } failure:^{ xLog(@"主动挂断失败"); self->hangUping = NO; [weakSelf dismissViewControllerAnimated:YES completion:nil]; }]; } else { if(self.isCall){ return; } //MARK: 收到设备主动挂断 后的 推送的 动作 //[UICommon MessageUpload:@""InfoWithStatus:[NSString stringWithFormat:@"%@ 拒绝了你的通话请求",cUser.cDevice.name]]; [UICommon MessageSuccessText:@"视频通话结束" isImg:NO]; AfterDispatch(1, ^{ [weakSelf dismissViewControllerAnimated:YES completion:nil]; }); } } } /** MARK: APP 被动挂断按钮 (接通前APP的挂断) */ - (IBAction)hangUpButton:(UIButton *)sender { [self stopRing]; [self leaveChannel]; if(!hangUping){ hangUping = YES; WEAKSELF //调 API 接口 下发指令给设备 上传 video_id [cUser activeHangUpVideoID:self.video_id WithDevice:self.device WithSuccess:^(id responseObject) { xLog(@"主动挂断成功"); [weakSelf dismissViewControllerAnimated:YES completion:nil]; self->hangUping = NO; } failure:^{ xLog(@"主动挂断失败"); self->hangUping = NO; }]; } } /** MARK: 离开通道 */ - (void)leaveChannel { xLog(@"调用离开通道接口"); if(self.alertView){ [self.alertView dismissAnimated:YES completionHandler:nil]; } WEAKSELF [self.agoraKit leaveChannel:^(AgoraChannelStats *stat) { //取消不自动锁屏 [UIApplication sharedApplication].idleTimerDisabled = NO; [weakSelf.remoteVideo removeFromSuperview]; [weakSelf.localVideo removeFromSuperview]; //停止定时器 [weakSelf _stopTimeTimer]; if(weakSelf.isCall){ //上传视频时间 NSMutableDictionary *dic = [NSMutableDictionary dictionary]; long tempTime = stat.duration-self->wait_duration; if(stat.duration - self->wait_duration < 0){ tempTime = 0; } [dic setValue:@(tempTime) forKey:@"duration"]; [dic setValue:@(self->wait_duration) forKey:@"wait_duration"];//wait_duration [dic setValue:@(weakSelf.videoSize.width) forKey:@"distinguishability_width"]; [dic setValue:@(weakSelf.videoSize.height) forKey:@"distinguishability_heiger"]; [dic setValue:self.video_id forKey:@"video_id"]; [cUser postVideoCallTimeParame:[dic copy] deviceModel:self.device success:^(id responseObject) { xLog(@"上传视频时间成功"); //MARK: 上传完视频时间后删除存储的 Key [UserDefaults removeObjectForKey:VideoTimeAndIDAndWHRecordKey]; } failure:^{ xLog(@"上传视频时间失败"); }]; } [weakSelf dismissViewControllerAnimated:YES completion:^{ }]; }]; } /** 用户在 视频通话 和 语音通话间切换 (暂时不用) */ - (IBAction)didClickVideoMuteButton:(UIButton *)sender { sender.selected = !sender.selected; [self.agoraKit muteLocalVideoStream:sender.selected]; //self.localVideo.hidden = sender.selected; } #pragma mark AgoraRtcEngineDelegate /// 发生错误回调 - (void)rtcEngine:(AgoraRtcEngineKit *_Nonnull)engine didOccurError:(AgoraErrorCode)errorCode{ xLog(@"===发生错误回调 errorCode:%ld",errorCode); } /// Token 服务即将过期回调 - (void)rtcEngine:(AgoraRtcEngineKit *)engine tokenPrivilegeWillExpire:(NSString *)token { xLog(@"Token 服务即将过期回调 token:%@",token); } /// Token 过期回调 -(void)rtcEngineRequestToken:(AgoraRtcEngineKit *)engine { xLog(@"Token 过期回调"); } - (void)rtcEngine:(AgoraRtcEngineKit *)engine didJoinedOfUid:(NSUInteger)uid elapsed:(NSInteger)elapsed { NSLog(@"\n\n\n\n远端用户加入频道\n\n\n\n\n"); [self stopRing]; if(self.isCall == NO){ //MARK: 赋值等待时间 wait_duration = self.timeLength; self.timeLength = 0; [self _stopTimeTimer]; [self _startTimeTimer]; } self.isCall = YES; if (self.remoteVideo.hidden) { self.remoteVideo.hidden = NO; } AgoraRtcVideoCanvas *videoCanvas = [[AgoraRtcVideoCanvas alloc] init]; videoCanvas.uid = uid; videoCanvas.renderMode = AgoraVideoRenderModeHidden; videoCanvas.view = self.remoteVideo; [self.agoraKit setupRemoteVideo:videoCanvas]; } - (void)rtcEngine:(AgoraRtcEngineKit *)engine didJoinChannel:(NSString *)channel withUid:(NSUInteger)uid elapsed:(NSInteger) elapsed { NSLog(@"*本地用户成功加入指定通道时发生。"); } - (void)rtcEngine:(AgoraRtcEngineKit *)engine remoteVideoStateChangedOfUid:(NSUInteger)uid state:(AgoraVideoRemoteState)state reason:(AgoraVideoRemoteReason)reason elapsed:(NSInteger)elapsed { NSLog(@"************************"); //self.isCall = YES; } - (void)rtcEngine:(AgoraRtcEngineKit *)engine localVideoStats:(AgoraRtcLocalVideoStats * _Nonnull)stats { NSLog(@"本地视频流"); } ////MARK: 视频的暂停 和 恢复 //- (void)rtcEngine:(AgoraRtcEngineKit *)engine didVideoMuted:(BOOL)muted byUid:(NSUInteger)uid { // NSLog(@"//MARK: 视频的暂停 和 恢复"); // self.remoteVideo.hidden = muted; //} //MARK: 频道的统计数据 回调 每两秒触发一次。 -(void)rtcEngine:(AgoraRtcEngineKit *)engine reportRtcStats:(AgoraChannelStats *)stats { NSLog(@"//MARK: 频道的统计数据 回调 每两秒触发一次。"); if(self.isCall) { // self.timeLength = (int)stats.duration - wait_duration; //MARK:记录视频通话时间 [UserDefaults setValue:[NSString stringWithFormat:@"%@&%@&%@&%@&%@",@(stats.duration),self.video_id,@(self.videoSize.width),@(self.videoSize.height),@(wait_duration)] forKey:VideoTimeAndIDAndWHRecordKey]; } } //MARK: 用户离线回调 - (void)rtcEngine:(AgoraRtcEngineKit *)engine didOfflineOfUid:(NSUInteger)uid reason:(AgoraUserOfflineReason)reason { self.remoteVideo.hidden = true; switch (reason) { case AgoraUserOfflineReasonQuit: //用户主动离开 xLog(@"用户主动离开"); [self leaveChannel]; break; case AgoraUserOfflineReasonBecomeAudience: //用户身份从主播切换为观众时触发 xLog(@"用户身份从主播切换为观众时触发"); break; case AgoraUserOfflineReasonDropped: //因过长时间收不到对方数据包,超时掉线。注意:由于 SDK 使用的是不可靠通道,也有可能对方主动离开本方没收到对方离开消息而误判为超时掉线 xLog(@"因过长时间收不到对方数据包,超时掉线。注意:由于 SDK 使用的是不可靠通道,也有可能对方主动离开本方没收到对方离开消息而误判为超时掉线"); break; } if(reason == AgoraUserOfflineReasonBecomeAudience) { return; } if(uid == self.device_uid) { [self leaveChannel]; [UICommon MessageSuccessText:[NSString stringWithFormat:@"%@已挂断",cUser.cDevice.name] isImg:NO]; } if(uid == self.uid){ xLog(@"自己离开通道"); } } #pragma mark - 时间定时器 - (void)timeTimerAction:(id)sender { self.timeLength += 1; if(self.isCall == NO) { //未接通的情况 if(self.timeLength == self.wait_time) { wait_duration = self.wait_time; [self leaveChannel]; WEAKSELF [UICommon MessageSuccessText:[NSString stringWithFormat:@"%@ 未接听",self.device.name] isImg:NO]; AfterDispatch(1, ^{ [weakSelf dismissViewControllerAnimated:YES completion:nil]; }); [self _stopTimeTimer]; return; } else { wait_duration = self.timeLength; } } if(self.timeLength == self.limit_time - DefineVideoLimitBeforeShowTime){ self.alertView = [[LGAlertView alloc] initWithTitle:@"提示" message:@"为防止设备温度过高,即将结束通话,稍后可正常使用" style:LGAlertViewStyleAlert buttonTitles:@[@"确定"] cancelButtonTitle:@"" destructiveButtonTitle:nil actionHandler:^(LGAlertView *alertView, NSString *title, NSUInteger index) { } cancelHandler:^(LGAlertView *alertView) { } destructiveHandler:nil]; [self.alertView showAnimated:YES completionHandler:nil]; } //限制时间, 不能和设备视频太长时间 默认是 180s (3分钟) if(self.timeLength == self.limit_time) { [self hangUpButton:nil]; return; } if(self.isCall) { int hour = self.timeLength / 3600; int m = (self.timeLength - hour * 3600) / 60; int s = self.timeLength - hour * 3600 - m * 60; if (hour > 0) { self.timeLabel.text = [NSString stringWithFormat:@"%02i:%02i:%02i", hour, m, s]; } else if(m > 0) { self.timeLabel.text = [NSString stringWithFormat:@"%02i:%02i", m, s]; } else { self.timeLabel.text = [NSString stringWithFormat:@"00:%02i", s]; } } } - (void)_startTimeTimer { [self _stopTimeTimer]; self.timeLength = 0; self.timeTimer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(timeTimerAction:) userInfo:nil repeats:YES]; } - (void)_stopTimeTimer { if (self.timeTimer) { [self.timeTimer invalidate]; self.timeTimer = nil; } } //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; } } -(void)viewDidDisappear:(BOOL)animated { [super viewDidDisappear:animated]; [self stopRing]; //停止响铃 //移除通知 [[NSNotificationCenter defaultCenter] removeObserver:self name:AccountMessageNotification object:nil]; [[NSNotificationCenter defaultCenter] removeObserver:self]; } - (void)viewWillAppear:(BOOL)animated { [super viewWillAppear:animated]; [self initializeAgoraEngine]; WEAKSELF if(!self.isReceiveCall) { //主动拨打 self.hangUpBtn.hidden = NO; self.headImageView.hidden = NO; self.nameLabel.hidden = NO; self.statusLabel.hidden = NO; self.statusLabel.text = @"正在呼叫中..."; dispatch_async(dispatch_get_main_queue(), ^{ [weakSelf playRing:@"ring"]; }); [self joinChannel]; } else { //被动接听 self.headImageView.hidden = NO; self.nameLabel.hidden = NO; self.statusLabel.hidden = NO; self.statusLabel.text = @"连接中"; self.lefthangUpBtn.hidden = NO; self.answerBtn.hidden = NO; if([UIApplication sharedApplication].applicationState == UIApplicationStateActive){ dispatch_async(dispatch_get_main_queue(), ^{ [weakSelf playRing:@"tones"]; }); } } } - (void)setIsCall:(BOOL)isCall { _isCall = isCall; if(isCall) { //隐藏 设备 头像 和 昵称 显示 (默认是显示的) self.headImageView.hidden = YES; self.nameLabel.hidden = YES; self.lefthangUpBtn.hidden = YES; self.answerBtn.hidden = YES; /// 接听按钮 self.statusLabel.hidden = YES; self.localVideo.hidden = NO; // 显示自己 self.timeLabel.hidden = NO; self.switchCameraBtn.hidden = NO;/// 切换摄像头 self.microphoneBtn.hidden = NO; /// 麦克风 self.muteBtn.hidden = NO; /// 静音按钮 self.onSwitchCameraBtn.hidden = NO; /// 摄像头开关 self.hangUpBtn.hidden = NO; /// 接通后挂断按钮 self.tonghuaLabel.hidden = NO; self.tonghuaLabel.text = [NSString stringWithFormat:@"与%@的对话",self.device.name]; } } //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([self.localVideo isEqual:selectView]) { self.localVideo.frame = CGRectMake(0, 0, ScreenWidth, ScreenHeight); self.remoteVideo.frame = tempRect; [self.view exchangeSubviewAtIndex:self.remoteVideo.getInSuperViewIndex withSubviewAtIndex:self.localVideo.getInSuperViewIndex]; }else{ self.remoteVideo.frame = CGRectMake(0, 0, ScreenWidth, ScreenHeight); self.localVideo.frame = tempRect; [self.view exchangeSubviewAtIndex:self.localVideo.getInSuperViewIndex withSubviewAtIndex:self.remoteVideo.getInSuperViewIndex]; } } } - (void)setBtnImageAndTitle:(UIButton *)button { CGFloat offset = 20.0f; button.titleEdgeInsets = UIEdgeInsetsMake(0,-button.imageView.frame.size.width,-button.imageView.frame.size.height-offset/2,0); // button.imageEdgeInsets = UIEdgeInsetsMake(-button.titleLabel.frame.size.height-offset/2,0,0,-button.titleLabel.frame.size.width); // 由于iOS8中titleLabel的size为0,用上面这样设置有问题,修改一下即可 button.imageEdgeInsets = UIEdgeInsetsMake(-button.titleLabel.intrinsicContentSize.height-offset/2,0,0,-button.titleLabel.intrinsicContentSize.width); } -(void)dealloc { [[NSNotificationCenter defaultCenter] removeObserver:self]; } - (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; // Dispose of any resources that can be recreated. } @end