NTESVideoChatViewController.m 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574
  1. //
  2. // NTESVideoChatViewController.m
  3. // NIM
  4. //
  5. // Created by chris on 15/5/5.
  6. // Copyright (c) 2015年 Netease. All rights reserved.
  7. //
  8. #import "NTESVideoChatViewController.h"
  9. #import "UIView+Toast.h"
  10. #import "NTESTimerHolder.h"
  11. //#import "NTESAudioChatViewController.h"
  12. //#import "NTESMainTabController.h"
  13. #import "NTESNetCallChatInfo.h"
  14. //#import "NTESSessionUtil.h"
  15. //#import "NTESVideoChatNetStatusView.h"
  16. #import "NTESGLView.h"
  17. #import "NTESBundleSetting.h"
  18. //#import "NTESRecordSelectView.h"
  19. #import "UIView+NTES.h"
  20. #define NTESUseGLView
  21. @interface NTESVideoChatViewController ()
  22. @property (nonatomic,assign) NIMNetCallCamera cameraType;
  23. @property (nonatomic,strong) CALayer *localVideoLayer;
  24. @property (nonatomic,assign) BOOL oppositeCloseVideo;
  25. #if defined (NTESUseGLView)
  26. @property (nonatomic, strong) NTESGLView *remoteGLView;
  27. #endif
  28. @property (nonatomic,weak) UIView *localView;
  29. @property (nonatomic,weak) UIView *localPreView;
  30. @property (nonatomic, assign) BOOL calleeBasy;
  31. @end
  32. @implementation NTESVideoChatViewController
  33. - (instancetype)initWithCallInfo:(NTESNetCallChatInfo *)callInfo
  34. {
  35. self = [self initWithNibName:nil bundle:nil];
  36. if (self) {
  37. self.callInfo = callInfo;
  38. self.callInfo.isMute = NO;
  39. self.callInfo.useSpeaker = NO;
  40. self.callInfo.disableCammera = NO;
  41. if (!self.localPreView) {
  42. //没有的话,尝试去取一把预览层(从视频切到语音再切回来的情况下是会有的)
  43. self.localPreView = [NIMAVChatSDK sharedSDK].netCallManager.localPreview;
  44. }
  45. [[NIMAVChatSDK sharedSDK].netCallManager switchType:NIMNetCallMediaTypeVideo];
  46. }
  47. return self;
  48. }
  49. - (instancetype)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil{
  50. self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
  51. if (self) {
  52. self.callInfo.callType = NIMNetCallTypeVideo;
  53. _cameraType = [[NTESBundleSetting sharedConfig] startWithBackCamera] ? NIMNetCallCameraBack :NIMNetCallCameraFront;
  54. }
  55. return self;
  56. }
  57. - (void)viewDidLoad {
  58. self.localView = self.smallVideoView;
  59. [super viewDidLoad];
  60. if (self.localPreView) {
  61. self.localPreView.frame = self.localView.bounds;
  62. [self.localView addSubview:self.localPreView];
  63. }
  64. [self initUI];
  65. }
  66. - (void)viewWillAppear:(BOOL)animated{
  67. self.tabBarController.tabBar.hidden = YES;
  68. self.view.frame = CGRectMake(0, 0, ScreenWidth, ScreenHeight+60);
  69. self.navigationController.navigationBar.hidden = YES;
  70. [self changeLoginState:@"2"];
  71. }
  72. - (void)viewWillDisappear:(BOOL)animated{
  73. [self changeLoginState:@"1"];
  74. NSTimeInterval time = [NSDate date].timeIntervalSince1970;
  75. NSTimeInterval duration = time - self.callInfo.startTime;
  76. [self.delegate getDuration:[NSString stringWithFormat:@"%02d",(int)duration/60] videoPK:self.videoPK];
  77. self.tabBarController.tabBar.hidden = NO;
  78. self.navigationController.navigationBar.hidden = NO;
  79. }
  80. - (void)changeLoginState:(NSString *)state{
  81. NSString *str = [NSString stringWithFormat:@"%@modelInfo?action=doPutOnline&modelpk=%@&online=%@",imageURl,[ModelUser user].modelpk,state];
  82. [[AHHttpManager sharedManager]POST:str parameters:nil success:^(id responseObject) {
  83. NSLog(@"%@",responseObject);
  84. if ([[responseObject objectForKey:@"msg"]isEqualToString:@"success"]) {
  85. }else{
  86. }
  87. } failure:^(NSError *error) {
  88. NSLog(@"error = %@",error);
  89. }];
  90. }
  91. - (void)initUI
  92. {
  93. self.localRecordingView.layer.cornerRadius = 10.0;
  94. self.localRecordingRedPoint.layer.cornerRadius = 4.0;
  95. self.lowMemoryView.layer.cornerRadius = 10.0;
  96. self.lowMemoryRedPoint.layer.cornerRadius = 4.0;
  97. self.refuseBtn.exclusiveTouch = YES;
  98. self.acceptBtn.exclusiveTouch = YES;
  99. if ([[UIApplication sharedApplication] applicationState] == UIApplicationStateActive) {
  100. [self initRemoteGLView];
  101. }
  102. }
  103. - (void)initRemoteGLView {
  104. #if defined (NTESUseGLView)
  105. _remoteGLView = [[NTESGLView alloc] initWithFrame:_bigVideoView.bounds];
  106. [_remoteGLView setContentMode:[[NTESBundleSetting sharedConfig] videochatRemoteVideoContentMode]];
  107. [_remoteGLView setBackgroundColor:[UIColor clearColor]];
  108. _remoteGLView.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleBottomMargin | UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
  109. [_bigVideoView addSubview:_remoteGLView];
  110. #endif
  111. }
  112. #pragma mark - Call Life
  113. - (void)startByCaller{
  114. [super startByCaller];
  115. [self startInterface];
  116. }
  117. - (void)startByCallee{
  118. [super startByCallee];
  119. [self waitToCallInterface];
  120. }
  121. - (void)onCalling{
  122. [super onCalling];
  123. [self acceptChat];
  124. [self videoCallingInterface];
  125. }
  126. - (void)waitForConnectiong{
  127. [super waitForConnectiong];
  128. [self connectingInterface];
  129. }
  130. - (void)onCalleeBusy
  131. {
  132. _calleeBasy = YES;
  133. if (_localPreView)
  134. {
  135. [_localPreView removeFromSuperview];
  136. }
  137. }
  138. #pragma mark - Interface
  139. //正在接听中界面
  140. - (void)startInterface{
  141. self.acceptBtn.hidden = YES;
  142. self.refuseBtn.hidden = YES;
  143. self.hungUpBtn.hidden = NO;
  144. self.connectingLabel.hidden = NO;
  145. self.connectingLabel.text = @"正在呼叫,请稍候...";
  146. self.switchModelBtn.hidden = YES;
  147. self.switchCameraBtn.hidden = NO;
  148. self.muteBtn.hidden = NO;
  149. self.disableCameraBtn.hidden = NO;
  150. self.localRecordBtn.hidden = NO;
  151. self.muteBtn.enabled = NO;
  152. self.disableCameraBtn.enabled = NO;
  153. self.localRecordBtn.enabled = NO;
  154. self.localRecordingView.hidden = YES;
  155. self.lowMemoryView.hidden = YES;
  156. [self.hungUpBtn removeTarget:self action:NULL forControlEvents:UIControlEventTouchUpInside];
  157. [self.hungUpBtn addTarget:self action:@selector(hangup) forControlEvents:UIControlEventTouchUpInside];
  158. self.localView = self.bigVideoView;
  159. }
  160. //选择是否接听界面
  161. - (void)waitToCallInterface{
  162. self.acceptBtn.hidden = NO;
  163. self.refuseBtn.hidden = NO;
  164. self.hungUpBtn.hidden = YES;
  165. NSString *nick = [self showNick:self.callInfo.caller inSession:nil];
  166. self.connectingLabel.text = [nick stringByAppendingString:@"的来电"];
  167. self.muteBtn.hidden = YES;
  168. self.switchCameraBtn.hidden = YES;
  169. self.disableCameraBtn.hidden = YES;
  170. self.localRecordBtn.hidden = YES;
  171. self.localRecordingView.hidden = YES;
  172. self.lowMemoryView.hidden = YES;
  173. self.switchModelBtn.hidden = YES;
  174. self.BindView.hidden = YES;
  175. }
  176. - (NSString *)showNick:(NSString*)uid inSession:(NIMSession*)session{
  177. NSString *nickname = nil;
  178. if (session.sessionType == NIMSessionTypeTeam)
  179. {
  180. NIMTeamMember *member = [[NIMSDK sharedSDK].teamManager teamMember:uid inTeam:session.sessionId];
  181. nickname = member.nickname;
  182. }
  183. if (!nickname.length) {
  184. NIMKitInfo *info = [[NIMKit sharedKit] infoByUser:uid option:nil];
  185. nickname = info.showName;
  186. }
  187. return nickname;
  188. }
  189. //连接对方界面
  190. - (void)connectingInterface{
  191. self.acceptBtn.hidden = YES;
  192. self.refuseBtn.hidden = YES;
  193. self.hungUpBtn.hidden = NO;
  194. self.connectingLabel.hidden = NO;
  195. self.connectingLabel.text = @"正在连接对方...请稍后...";
  196. self.switchModelBtn.hidden = YES;
  197. self.switchCameraBtn.hidden = YES;
  198. self.muteBtn.hidden = YES;
  199. self.disableCameraBtn.hidden = YES;
  200. self.localRecordBtn.hidden = YES;
  201. self.localRecordingView.hidden = YES;
  202. self.lowMemoryView.hidden = YES;
  203. self.BindView.hidden = NO;
  204. [self.hungUpBtn removeTarget:self action:NULL forControlEvents:UIControlEventTouchUpInside];
  205. [self.hungUpBtn addTarget:self action:@selector(hangup) forControlEvents:UIControlEventTouchUpInside];
  206. }
  207. //接听中界面(视频)
  208. - (void)videoCallingInterface{
  209. // NIMNetCallNetStatus status = [[NIMAVChatSDK sharedSDK].netCallManager netStatus:self.peerUid];
  210. // [self.netStatusView refreshWithNetState:status];
  211. self.acceptBtn.hidden = YES;
  212. self.refuseBtn.hidden = YES;
  213. self.hungUpBtn.hidden = NO;
  214. self.connectingLabel.hidden = YES;
  215. self.muteBtn.hidden = NO;
  216. self.switchCameraBtn.hidden = NO;
  217. self.disableCameraBtn.hidden = NO;
  218. self.localRecordBtn.hidden = NO;
  219. self.switchModelBtn.hidden = NO;
  220. self.muteBtn.enabled = YES;
  221. self.disableCameraBtn.enabled = YES;
  222. self.localRecordBtn.enabled = YES;
  223. self.muteBtn.selected = self.callInfo.isMute;
  224. self.disableCameraBtn.selected = self.callInfo.disableCammera;
  225. self.localRecordBtn.selected = ![self allRecordsStopped];
  226. ;
  227. self.localRecordingView.hidden = [self allRecordsStopped];
  228. ;
  229. self.lowMemoryView.hidden = YES;
  230. self.BindView.hidden = NO;
  231. [self.switchModelBtn setTitle:@"语音模式" forState:UIControlStateNormal];
  232. [self.hungUpBtn removeTarget:self action:NULL forControlEvents:UIControlEventTouchUpInside];
  233. [self.hungUpBtn addTarget:self action:@selector(hangup) forControlEvents:UIControlEventTouchUpInside];
  234. // self.localVideoLayer.hidden = NO;
  235. self.localPreView.hidden = NO;
  236. }
  237. ////切换接听中界面(语音)
  238. //- (void)audioCallingInterface{
  239. //
  240. // NTESAudioChatViewController *vc = [[NTESAudioChatViewController alloc] initWithCallInfo:self.callInfo];
  241. // [UIView beginAnimations:nil context:NULL];
  242. // [UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
  243. // [UIView setAnimationDuration:0.75];
  244. // [self.navigationController pushViewController:vc animated:NO];
  245. // [UIView setAnimationTransition:UIViewAnimationTransitionFlipFromRight forView:self.navigationController.view cache:NO];
  246. // [UIView commitAnimations];
  247. // NSMutableArray * vcs = [self.navigationController.viewControllers mutableCopy];
  248. // [vcs removeObject:self];
  249. // self.navigationController.viewControllers = vcs;
  250. //}
  251. - (void)udpateLowSpaceWarning:(BOOL)show {
  252. self.lowMemoryView.hidden = !show;
  253. self.localRecordingView.hidden = show;
  254. }
  255. #pragma mark - IBAction
  256. - (IBAction)acceptToCall:(id)sender{
  257. BOOL accept = (sender == self.acceptBtn);
  258. //防止用户在点了接收后又点拒绝的情况
  259. [self response:accept];
  260. }
  261. - (IBAction)mute:(BOOL)sender{
  262. self.callInfo.isMute = !self.callInfo.isMute;
  263. // self.player.volume = !self.callInfo.isMute;
  264. [[NIMAVChatSDK sharedSDK].netCallManager setMute:self.callInfo.isMute];
  265. self.muteBtn.selected = self.callInfo.isMute;
  266. }
  267. - (IBAction)switchCamera:(id)sender{
  268. if (self.cameraType == NIMNetCallCameraFront) {
  269. self.cameraType = NIMNetCallCameraBack;
  270. }else{
  271. self.cameraType = NIMNetCallCameraFront;
  272. }
  273. [[NIMAVChatSDK sharedSDK].netCallManager switchCamera:self.cameraType];
  274. self.switchCameraBtn.selected = (self.cameraType == NIMNetCallCameraBack);
  275. }
  276. - (IBAction)disableCammera:(id)sender{
  277. self.callInfo.disableCammera = !self.callInfo.disableCammera;
  278. [[NIMAVChatSDK sharedSDK].netCallManager setCameraDisable:self.callInfo.disableCammera];
  279. self.disableCameraBtn.selected = self.callInfo.disableCammera;
  280. if (self.callInfo.disableCammera) {
  281. [self.localPreView removeFromSuperview];
  282. [[NIMAVChatSDK sharedSDK].netCallManager control:self.callInfo.callID type:NIMNetCallControlTypeCloseVideo];
  283. }else{
  284. [self.localView addSubview:self.localPreView];
  285. [[NIMAVChatSDK sharedSDK].netCallManager control:self.callInfo.callID type:NIMNetCallControlTypeOpenVideo];
  286. }
  287. }
  288. - (IBAction)localRecord:(id)sender {
  289. //出现录制选择框
  290. if ([self allRecordsStopped]) {
  291. [self showRecordSelectView:YES];
  292. }
  293. //同时停止所有录制
  294. else
  295. {
  296. //结束语音对话
  297. if (self.callInfo.audioConversation) {
  298. [self stopAudioRecording];
  299. if([self allRecordsStopped])
  300. {
  301. self.localRecordBtn.selected = NO;
  302. self.localRecordingView.hidden = YES;
  303. self.lowMemoryView.hidden = YES;
  304. }
  305. }
  306. [self stopRecordTaskWithVideo:YES];
  307. }
  308. }
  309. - (IBAction)switchCallingModel:(id)sender{
  310. [[NIMAVChatSDK sharedSDK].netCallManager control:self.callInfo.callID type:NIMNetCallControlTypeToAudio];
  311. // [self switchToAudio];
  312. }
  313. #pragma mark - NTESRecordSelectViewDelegate
  314. -(void)onRecordWithAudioConversation:(BOOL)audioConversationOn myMedia:(BOOL)myMediaOn otherSideMedia:(BOOL)otherSideMediaOn
  315. {
  316. if (audioConversationOn) {
  317. //开始语音对话
  318. if ([self startAudioRecording]) {
  319. self.callInfo.audioConversation = YES;
  320. self.localRecordBtn.selected = YES;
  321. self.localRecordingView.hidden = NO;
  322. self.lowMemoryView.hidden = YES;
  323. }
  324. }
  325. [self recordWithAudioConversation:audioConversationOn myMedia:myMediaOn otherSideMedia:otherSideMediaOn video:YES];
  326. }
  327. #pragma mark - NIMNetCallManagerDelegate
  328. - (void)onLocalDisplayviewReady:(UIView *)displayView
  329. {
  330. if (_calleeBasy) {
  331. return;
  332. }
  333. if (self.localPreView) {
  334. [self.localPreView removeFromSuperview];
  335. }
  336. self.localPreView = displayView;
  337. displayView.frame = self.localView.bounds;
  338. [self.localView addSubview:displayView];
  339. }
  340. #if defined(NTESUseGLView)
  341. - (void)onRemoteYUVReady:(NSData *)yuvData
  342. width:(NSUInteger)width
  343. height:(NSUInteger)height
  344. from:(NSString *)user
  345. {
  346. if (([[UIApplication sharedApplication] applicationState] == UIApplicationStateActive) && !self.oppositeCloseVideo) {
  347. if (!_remoteGLView) {
  348. [self initRemoteGLView];
  349. }
  350. [_remoteGLView render:yuvData width:width height:height];
  351. }
  352. }
  353. #else
  354. - (void)onRemoteImageReady:(CGImageRef)image{
  355. if (self.oppositeCloseVideo) {
  356. return;
  357. }
  358. self.bigVideoView.contentMode = UIViewContentModeScaleAspectFill;
  359. self.bigVideoView.image = [UIImage imageWithCGImage:image];
  360. }
  361. #endif
  362. - (void)onControl:(UInt64)callID
  363. from:(NSString *)user
  364. type:(NIMNetCallControlType)control{
  365. [super onControl:callID from:user type:control];
  366. switch (control) {
  367. case NIMNetCallControlTypeToAudio:
  368. // [self switchToAudio];
  369. break;
  370. case NIMNetCallControlTypeCloseVideo:
  371. [self resetRemoteImage];
  372. self.oppositeCloseVideo = YES;
  373. [self.view makeToast:@"对方关闭了摄像头"
  374. duration:2
  375. position:CSToastPositionCenter];
  376. break;
  377. case NIMNetCallControlTypeOpenVideo:
  378. self.oppositeCloseVideo = NO;
  379. [self.view makeToast:@"对方开启了摄像头"
  380. duration:2
  381. position:CSToastPositionCenter];
  382. break;
  383. default:
  384. break;
  385. }
  386. }
  387. -(void)onCallEstablished:(UInt64)callID
  388. {
  389. if (self.callInfo.callID == callID) {
  390. [super onCallEstablished:callID];
  391. self.durationLabel.hidden = NO;
  392. self.durationLabel.text = self.durationDesc;
  393. if (self.localView == self.bigVideoView) {
  394. self.localView = self.smallVideoView;
  395. if (self.localPreView) {
  396. [self onLocalDisplayviewReady:self.localPreView];
  397. }
  398. }
  399. }
  400. }
  401. //- (void)onNetStatus:(NIMNetCallNetStatus)status user:(NSString *)user
  402. //{
  403. // if ([user isEqualToString:self.peerUid]) {
  404. // [self.netStatusView refreshWithNetState:status];
  405. // }
  406. //}
  407. - (void)onRecordStarted:(UInt64)callID fileURL:(NSURL *)fileURL uid:(NSString *)userId
  408. {
  409. [super onRecordStarted:callID fileURL:fileURL uid:userId];
  410. if (self.callInfo.callID == callID) {
  411. self.localRecordBtn.selected = YES;
  412. self.localRecordingView.hidden = NO;
  413. self.lowMemoryView.hidden = YES;
  414. }
  415. }
  416. - (void)onRecordError:(NSError *)error
  417. callID:(UInt64)callID
  418. uid:(NSString *)userId;
  419. {
  420. [super onRecordError:error callID:callID uid:userId];
  421. if (self.callInfo.callID == callID) {
  422. //判断是否全部结束
  423. if([self allRecordsStopped])
  424. {
  425. self.localRecordBtn.selected = NO;
  426. self.localRecordingView.hidden = YES;
  427. self.lowMemoryView.hidden = YES;
  428. }
  429. }
  430. }
  431. - (void) onRecordStopped:(UInt64)callID
  432. fileURL:(NSURL *)fileURL
  433. uid:(NSString *)userId;
  434. {
  435. [super onRecordStopped:callID fileURL:fileURL uid:userId];
  436. if (self.callInfo.callID == callID) {
  437. if([self allRecordsStopped])
  438. {
  439. self.localRecordBtn.selected = NO;
  440. self.localRecordingView.hidden = YES;
  441. self.lowMemoryView.hidden = YES;
  442. }
  443. }
  444. }
  445. #pragma mark - M80TimerHolderDelegate
  446. - (void)onNTESTimerFired:(NTESTimerHolder *)holder{
  447. [super onNTESTimerFired:holder];
  448. self.durationLabel.text = self.durationDesc;
  449. }
  450. #pragma mark - Misc
  451. //- (void)switchToAudio{
  452. // [self audioCallingInterface];
  453. //}
  454. - (NSString*)durationDesc{
  455. if (!self.callInfo.startTime) {
  456. return @"";
  457. }
  458. NSTimeInterval time = [NSDate date].timeIntervalSince1970;
  459. NSTimeInterval duration = time - self.callInfo.startTime;
  460. return [NSString stringWithFormat:@"%02d:%02d",(int)duration/60,(int)duration%60];
  461. }
  462. - (void)resetRemoteImage{
  463. #if defined (NTESUseGLView)
  464. [self.remoteGLView render:nil width:0 height:0];
  465. #endif
  466. self.bigVideoView.image = [UIImage imageNamed:@"tonghuabeijing"];
  467. }
  468. - (void)acceptChat{
  469. NSString *now = [Helper getCurrentTimes];
  470. NSString *str = [NSString stringWithFormat:@"%@order?action=doAnsVChat&videopk=0&pk=%@&modelpk=%@&begdate=%@&hasanswer=1",imageURl,[Helper sharedAccount].accid,self.modelPk,now];
  471. NSLog(@"str = %@",str);
  472. [[AHHttpManager sharedManager]POST:[str stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding] parameters:nil success:^(id responseObject) {
  473. NSLog(@"%@",responseObject);
  474. if ([[responseObject objectForKey:@"msg"]isEqualToString:@"success"]) {
  475. self.videoPK = [responseObject objectForKey:@"videopk"];
  476. }else{
  477. //[MBProgressHUD showTextHUD:@"超时" inView:self.view hideAfterDelay:1];
  478. }
  479. } failure:^(NSError *error) {
  480. NSLog(@"error = %@",error);
  481. //[MBProgressHUD showTextHUD:@"超时" inView:self.view hideAfterDelay:1];
  482. }];
  483. }
  484. @end