// // NTESVideoChatViewController.m // NIM // // Created by chris on 15/5/5. // Copyright (c) 2015年 Netease. All rights reserved. // #import "NTESVideoChatViewController.h" #import "Toast+UIView.h" #import "NTESTimerHolder.h" #import "NTESAudioChatViewController.h" #import "NetCallChatInfo.h" #import "NTESSessionUtil.h" #import "NTESVideoChatNetStatusView.h" #import "NTESGLView.h" #import "NTESBundleSetting.h" #import "NTESRecordSelectView.h" #import "UIView+NTES.h" #define NTESUseGLView @interface NTESVideoChatViewController () @property (nonatomic,assign) NIMNetCallCamera cameraType; @property (nonatomic,strong) CALayer *localVideoLayer; @property (nonatomic,assign) BOOL oppositeCloseVideo; #if defined (NTESUseGLView) @property (nonatomic, strong) NTESGLView *remoteGLView; #endif @property (nonatomic,weak) UIView *localView; @end @implementation NTESVideoChatViewController - (instancetype)initWithCallInfo:(NetCallChatInfo *)callInfo { self = [self initWithNibName:nil bundle:nil]; if (self) { self.callInfo = callInfo; self.callInfo.isMute = NO; self.callInfo.useSpeaker = NO; self.callInfo.disableCammera = NO; if (!self.localVideoLayer) { //没有的话,尝试去取一把预览层(从视频切到语音再切回来的情况下是会有的) self.localVideoLayer = [NIMAVChatSDK sharedSDK].netCallManager.localPreviewLayer; } [[NIMAVChatSDK sharedSDK].netCallManager switchType:NIMNetCallMediaTypeVideo]; } return self; } - (instancetype)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil{ self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]; if (self) { self.callInfo.callType = NIMNetCallTypeVideo; _cameraType = [[NTESBundleSetting sharedConfig] startWithBackCamera] ? NIMNetCallCameraBack :NIMNetCallCameraFront; } return self; } - (void)viewDidLoad { self.localView = self.smallVideoView; [super viewDidLoad]; if (self.localVideoLayer) { [self.localView.layer addSublayer:self.localVideoLayer]; } [self initUI]; } - (void)initUI { self.localRecordingView.layer.cornerRadius = 10.0; self.localRecordingRedPoint.layer.cornerRadius = 4.0; self.lowMemoryView.layer.cornerRadius = 10.0; self.lowMemoryRedPoint.layer.cornerRadius = 4.0; self.refuseBtn.exclusiveTouch = YES; self.acceptBtn.exclusiveTouch = YES; if ([[UIApplication sharedApplication] applicationState] == UIApplicationStateActive) { [self initRemoteGLView]; } } - (void)initRemoteGLView { #if defined (NTESUseGLView) _remoteGLView = [[NTESGLView alloc] initWithFrame:_bigVideoView.bounds]; [_remoteGLView setContentMode:UIViewContentModeScaleAspectFit]; [_remoteGLView setBackgroundColor:[UIColor clearColor]]; _remoteGLView.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleBottomMargin | UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; [_bigVideoView addSubview:_remoteGLView]; #endif } #pragma mark - Call Life - (void)startByCaller{ [super startByCaller]; [self startInterface]; } - (void)startByCallee{ [super startByCallee]; [self waitToCallInterface]; } - (void)onCalling{ [super onCalling]; [self videoCallingInterface]; } - (void)waitForConnectiong{ [super waitForConnectiong]; [self connectingInterface]; } #pragma mark - Interface //正在接听中界面 - (void)startInterface{ self.acceptBtn.hidden = YES; self.refuseBtn.hidden = YES; self.hungUpBtn.hidden = NO; self.connectingLabel.hidden = NO; self.connectingLabel.text = @"正在呼叫,请稍候..."; self.switchModelBtn.hidden = YES; self.switchCameraBtn.hidden = NO; self.muteBtn.hidden = NO; self.disableCameraBtn.hidden = NO; self.localRecordBtn.hidden = NO; self.muteBtn.enabled = NO; self.disableCameraBtn.enabled = NO; self.localRecordBtn.enabled = NO; self.localRecordingView.hidden = YES; self.lowMemoryView.hidden = YES; [self.hungUpBtn removeTarget:self action:NULL forControlEvents:UIControlEventTouchUpInside]; [self.hungUpBtn addTarget:self action:@selector(hangup) forControlEvents:UIControlEventTouchUpInside]; self.localView = self.bigVideoView; } //选择是否接听界面 - (void)waitToCallInterface{ self.acceptBtn.hidden = NO; self.refuseBtn.hidden = NO; self.hungUpBtn.hidden = YES; NSString *nick = [NTESSessionUtil showNick:self.callInfo.caller inSession:nil]; self.connectingLabel.text = [nick stringByAppendingString:@"的来电"]; self.muteBtn.hidden = YES; self.switchCameraBtn.hidden = YES; self.disableCameraBtn.hidden = YES; self.localRecordBtn.hidden = YES; self.localRecordingView.hidden = YES; self.lowMemoryView.hidden = YES; self.switchModelBtn.hidden = YES; } //连接对方界面 - (void)connectingInterface{ self.acceptBtn.hidden = YES; self.refuseBtn.hidden = YES; self.hungUpBtn.hidden = NO; self.connectingLabel.hidden = NO; self.connectingLabel.text = @"正在连接对方...请稍后..."; self.switchModelBtn.hidden = YES; self.switchCameraBtn.hidden = YES; self.muteBtn.hidden = YES; self.disableCameraBtn.hidden = YES; self.localRecordBtn.hidden = YES; self.localRecordingView.hidden = YES; self.lowMemoryView.hidden = YES; [self.hungUpBtn removeTarget:self action:NULL forControlEvents:UIControlEventTouchUpInside]; [self.hungUpBtn addTarget:self action:@selector(hangup) forControlEvents:UIControlEventTouchUpInside]; } //接听中界面(视频) - (void)videoCallingInterface{ NIMNetCallNetStatus status = [[NIMAVChatSDK sharedSDK].netCallManager netStatus:self.peerUid]; [self.netStatusView refreshWithNetState:status]; self.acceptBtn.hidden = YES; self.refuseBtn.hidden = YES; self.hungUpBtn.hidden = NO; self.connectingLabel.hidden = YES; self.muteBtn.hidden = NO; self.switchCameraBtn.hidden = NO; self.disableCameraBtn.hidden = NO; self.localRecordBtn.hidden = NO; self.switchModelBtn.hidden = NO; self.muteBtn.enabled = YES; self.disableCameraBtn.enabled = YES; self.localRecordBtn.enabled = YES; self.muteBtn.selected = self.callInfo.isMute; self.disableCameraBtn.selected = self.callInfo.disableCammera; self.localRecordBtn.selected = ![self allRecordsStopped]; ; self.localRecordingView.hidden = [self allRecordsStopped]; ; self.lowMemoryView.hidden = YES; [self.switchModelBtn setTitle:@"语音模式" forState:UIControlStateNormal]; [self.hungUpBtn removeTarget:self action:NULL forControlEvents:UIControlEventTouchUpInside]; [self.hungUpBtn addTarget:self action:@selector(hangup) forControlEvents:UIControlEventTouchUpInside]; self.localVideoLayer.hidden = NO; } //切换接听中界面(语音) - (void)audioCallingInterface{ NTESAudioChatViewController *vc = [[NTESAudioChatViewController alloc] initWithCallInfo:self.callInfo]; [UIView beginAnimations:nil context:NULL]; [UIView setAnimationCurve:UIViewAnimationCurveEaseInOut]; [UIView setAnimationDuration:0.75]; [self.navigationController pushViewController:vc animated:NO]; [UIView setAnimationTransition:UIViewAnimationTransitionFlipFromRight forView:self.navigationController.view cache:NO]; [UIView commitAnimations]; NSMutableArray * vcs = [self.navigationController.viewControllers mutableCopy]; [vcs removeObject:self]; self.navigationController.viewControllers = vcs; } - (void)udpateLowSpaceWarning:(BOOL)show { self.lowMemoryView.hidden = !show; self.localRecordingView.hidden = show; } #pragma mark - IBAction - (IBAction)acceptToCall:(id)sender{ BOOL accept = (sender == self.acceptBtn); //防止用户在点了接收后又点拒绝的情况 [self response:accept]; } - (IBAction)mute:(BOOL)sender{ self.callInfo.isMute = !self.callInfo.isMute; self.player.volume = !self.callInfo.isMute; [[NIMAVChatSDK sharedSDK].netCallManager setMute:self.callInfo.isMute]; self.muteBtn.selected = self.callInfo.isMute; } - (IBAction)switchCamera:(id)sender{ if (self.cameraType == NIMNetCallCameraFront) { self.cameraType = NIMNetCallCameraBack; }else{ self.cameraType = NIMNetCallCameraFront; } [[NIMAVChatSDK sharedSDK].netCallManager switchCamera:self.cameraType]; self.switchCameraBtn.selected = (self.cameraType == NIMNetCallCameraBack); } - (IBAction)disableCammera:(id)sender{ self.callInfo.disableCammera = !self.callInfo.disableCammera; [[NIMAVChatSDK sharedSDK].netCallManager setCameraDisable:self.callInfo.disableCammera]; self.disableCameraBtn.selected = self.callInfo.disableCammera; if (self.callInfo.disableCammera) { [self.localVideoLayer removeFromSuperlayer]; [[NIMAVChatSDK sharedSDK].netCallManager control:self.callInfo.callID type:NIMNetCallControlTypeCloseVideo]; }else{ [self.localView.layer addSublayer:self.localVideoLayer]; [[NIMAVChatSDK sharedSDK].netCallManager control:self.callInfo.callID type:NIMNetCallControlTypeOpenVideo]; } } - (IBAction)localRecord:(id)sender { //出现录制选择框 if ([self allRecordsStopped]) { [self showRecordSelectView:YES]; } //同时停止所有录制 else { //结束语音对话 if (self.callInfo.audioConversation) { [self stopAudioRecording]; if([self allRecordsStopped]) { self.localRecordBtn.selected = NO; self.localRecordingView.hidden = YES; self.lowMemoryView.hidden = YES; } } [self stopRecordTaskWithVideo:YES]; } } - (IBAction)switchCallingModel:(id)sender{ [[NIMAVChatSDK sharedSDK].netCallManager control:self.callInfo.callID type:NIMNetCallControlTypeToAudio]; [self switchToAudio]; } #pragma mark - NTESRecordSelectViewDelegate -(void)onRecordWithAudioConversation:(BOOL)audioConversationOn myMedia:(BOOL)myMediaOn otherSideMedia:(BOOL)otherSideMediaOn { if (audioConversationOn) { //开始语音对话 if ([self startAudioRecording]) { self.callInfo.audioConversation = YES; self.localRecordBtn.selected = YES; self.localRecordingView.hidden = NO; self.lowMemoryView.hidden = YES; } } [self recordWithAudioConversation:audioConversationOn myMedia:myMediaOn otherSideMedia:otherSideMediaOn video:YES]; } #pragma mark - NIMNetCallManagerDelegate - (void)setLocalVideoLayer:(CALayer *)localVideoLayer{ _localVideoLayer = localVideoLayer; } - (void)onLocalPreviewReady:(CALayer *)layer{ if (self.localVideoLayer) { [self.localVideoLayer removeFromSuperlayer]; } self.localVideoLayer = layer; layer.frame = self.localView.bounds; [self.localView.layer addSublayer:layer]; } #if defined(NTESUseGLView) - (void)onRemoteYUVReady:(NSData *)yuvData width:(NSUInteger)width height:(NSUInteger)height from:(NSString *)user { if (([[UIApplication sharedApplication] applicationState] == UIApplicationStateActive) && !self.oppositeCloseVideo) { if (!_remoteGLView) { [self initRemoteGLView]; } [_remoteGLView render:yuvData width:width height:height]; } } #else - (void)onRemoteImageReady:(CGImageRef)image{ if (self.oppositeCloseVideo) { return; } self.bigVideoView.contentMode = UIViewContentModeScaleAspectFill; self.bigVideoView.image = [UIImage imageWithCGImage:image]; } #endif - (void)onControl:(UInt64)callID from:(NSString *)user type:(NIMNetCallControlType)control{ [super onControl:callID from:user type:control]; switch (control) { case NIMNetCallControlTypeToAudio: [self switchToAudio]; break; case NIMNetCallControlTypeCloseVideo: [self resetRemoteImage]; self.oppositeCloseVideo = YES; [self.view makeToast:@"对方关闭了摄像头" ]; break; case NIMNetCallControlTypeOpenVideo: self.oppositeCloseVideo = NO; [self.view makeToast:@"对方开启了摄像头" ]; break; default: break; } } -(void)onCallEstablished:(UInt64)callID { if (self.callInfo.callID == callID) { [super onCallEstablished:callID]; self.durationLabel.hidden = NO; self.durationLabel.text = self.durationDesc; if (self.localView == self.bigVideoView) { self.localView = self.smallVideoView; if (self.localVideoLayer) { [self onLocalPreviewReady:self.localVideoLayer]; } } } } - (void)onNetStatus:(NIMNetCallNetStatus)status user:(NSString *)user { if ([user isEqualToString:self.peerUid]) { [self.netStatusView refreshWithNetState:status]; } } - (void)onRecordStarted:(UInt64)callID fileURL:(NSURL *)fileURL uid:(NSString *)userId { [super onRecordStarted:callID fileURL:fileURL uid:userId]; if (self.callInfo.callID == callID) { self.localRecordBtn.selected = YES; self.localRecordingView.hidden = NO; self.lowMemoryView.hidden = YES; } } - (void)onRecordError:(NSError *)error callID:(UInt64)callID uid:(NSString *)userId; { [super onRecordError:error callID:callID uid:userId]; if (self.callInfo.callID == callID) { //判断是否全部结束 if([self allRecordsStopped]) { self.localRecordBtn.selected = NO; self.localRecordingView.hidden = YES; self.lowMemoryView.hidden = YES; } } } - (void) onRecordStopped:(UInt64)callID fileURL:(NSURL *)fileURL uid:(NSString *)userId; { [super onRecordStopped:callID fileURL:fileURL uid:userId]; if (self.callInfo.callID == callID) { if([self allRecordsStopped]) { self.localRecordBtn.selected = NO; self.localRecordingView.hidden = YES; self.lowMemoryView.hidden = YES; } } } #pragma mark - M80TimerHolderDelegate - (void)onNTESTimerFired:(NTESTimerHolder *)holder{ [super onNTESTimerFired:holder]; self.durationLabel.text = self.durationDesc; } #pragma mark - Misc - (void)switchToAudio{ [self audioCallingInterface]; } - (NSString*)durationDesc{ if (!self.callInfo.startTime) { return @""; } NSTimeInterval time = [NSDate date].timeIntervalSince1970; NSTimeInterval duration = time - self.callInfo.startTime; return [NSString stringWithFormat:@"%02d:%02d",(int)duration/60,(int)duration%60]; } - (void)resetRemoteImage{ #if defined (NTESUseGLView) [self.remoteGLView render:nil width:0 height:0]; #endif self.bigVideoView.image = [UIImage imageNamed:@"netcall_bkg.png"]; } @end