NTESVideoChatViewController.m 18 KB

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