WFCUVideoViewController.m 39 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928
  1. //
  2. // ViewController.m
  3. // WFDemo
  4. //
  5. // Created by heavyrain on 17/9/27.
  6. // Copyright © 2017年 WildFireChat. All rights reserved.
  7. //
  8. #import "WFCUVideoViewController.h"
  9. #import <AVFoundation/AVFoundation.h>
  10. #import <AVKit/AVKit.h>
  11. #if WFCU_SUPPORT_VOIP
  12. #import <WebRTC/WebRTC.h>
  13. #import <WFAVEngineKit/WFAVEngineKit.h>
  14. #import "WFCUFloatingWindow.h"
  15. #endif
  16. #import <SDWebImage/SDWebImage.h>
  17. #import <WFChatClient/WFCCConversation.h>
  18. #import "UIFont+YH.h"
  19. #import "UIColor+YH.h"
  20. #import "UIView+Toast.h"
  21. #import "WFCUImage.h"
  22. #import "WFZConferenceInfo.h"
  23. #import "WFCUUtilities.h"
  24. #import "WFCUConfigManager.h"
  25. #import <WFChatClient/WFCChatClient.h>
  26. @interface WFCUVideoViewController () <UITextFieldDelegate
  27. #if WFCU_SUPPORT_VOIP
  28. ,WFAVCallSessionDelegate
  29. #endif
  30. >
  31. #if WFCU_SUPPORT_VOIP
  32. @property (nonatomic, strong) UIView *bigVideoView;
  33. @property (nonatomic, strong) UIView *smallVideoView;
  34. @property (nonatomic, strong) UIButton *hangupButton;
  35. @property (nonatomic, strong) UIButton *answerButton;
  36. @property (nonatomic, strong) UIButton *switchCameraButton;
  37. @property (nonatomic, strong) UIButton *audioButton;
  38. @property (nonatomic, strong) UIButton *speakerButton;
  39. @property (nonatomic, strong) UIButton *downgradeButton;
  40. @property (nonatomic, strong) UIButton *videoButton;
  41. @property (nonatomic, strong) UIButton *scalingButton;
  42. @property (nonatomic, strong) UIButton *minimizeButton;
  43. @property (nonatomic, strong) UIImageView *portraitView;
  44. @property (nonatomic, strong) UIImageView *backGroudPortraitView;
  45. @property (nonatomic, strong) UILabel *userNameLabel;
  46. @property (nonatomic, strong) UILabel *stateLabel;
  47. @property (nonatomic, assign) BOOL swapVideoView;
  48. @property (nonatomic, strong) WFAVCallSession *currentSession;
  49. @property (nonatomic, assign) WFAVVideoScalingType scalingType;
  50. @property (nonatomic, assign) CGPoint panStartPoint;
  51. @property (nonatomic, assign) CGRect panStartVideoFrame;
  52. @property (nonatomic, strong) NSTimer *connectedTimer;
  53. #endif
  54. @end
  55. #define ButtonSize 90
  56. #define SmallVideoView 120
  57. #if !WFCU_SUPPORT_VOIP
  58. @interface WFAVCallSession : NSObject
  59. @end
  60. @implementation WFAVCallSession
  61. @end
  62. #endif
  63. @implementation WFCUVideoViewController
  64. #if !WFCU_SUPPORT_VOIP
  65. - (instancetype)initWithSession:(WFAVCallSession *)session {
  66. self = [super init];
  67. return self;
  68. }
  69. - (instancetype)initWithTargets:(NSArray<NSString *> *)targetIds conversation:(WFCCConversation *)conversation audioOnly:(BOOL)audioOnly {
  70. self = [super init];
  71. return self;
  72. }
  73. #else
  74. - (instancetype)initWithSession:(WFAVCallSession *)session {
  75. self = [super init];
  76. if (self) {
  77. self.currentSession = session;
  78. self.currentSession.delegate = self;
  79. [self didChangeState:kWFAVEngineStateIncomming];
  80. }
  81. return self;
  82. }
  83. - (instancetype)initWithTargets:(NSArray<NSString *> *)targetIds conversation:(WFCCConversation *)conversation audioOnly:(BOOL)audioOnly {
  84. self = [super init];
  85. if (self) {
  86. WFAVCallSession *session = [[WFAVEngineKit sharedEngineKit] startCall:targetIds
  87. audioOnly:audioOnly
  88. callExtra:nil
  89. conversation:conversation
  90. sessionDelegate:self];
  91. self.currentSession = session;
  92. }
  93. return self;
  94. }
  95. - (void)viewDidLoad {
  96. [super viewDidLoad];
  97. [self.view setBackgroundColor:[UIColor blackColor]];
  98. if(self.currentSession.state == kWFAVEngineStateIdle) {
  99. [self didCallEndWithReason:self.currentSession.endReason];
  100. return;
  101. }
  102. self.scalingType = kWFAVVideoScalingTypeAspectFit;
  103. self.bigVideoView = [[UIView alloc] initWithFrame:self.view.bounds];
  104. UITapGestureRecognizer *tapBigVideo = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(onClickedBigVideoView:)];
  105. [self.bigVideoView addGestureRecognizer:tapBigVideo];
  106. [self.view addSubview:self.bigVideoView];
  107. self.smallVideoView = [[UIView alloc] initWithFrame:CGRectMake(self.view.frame.size.width - SmallVideoView, [WFCUUtilities wf_navigationFullHeight], SmallVideoView, SmallVideoView * 4 /3)];
  108. [self.smallVideoView addGestureRecognizer:[[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(onSmallVideoPan:)]];
  109. [self.smallVideoView addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(onSmallVideoTaped:)]];
  110. [self.view addSubview:self.smallVideoView];
  111. if(self.currentSession.state == kWFAVEngineStateOutgoing && !self.currentSession.isAudioOnly) {
  112. [[WFAVEngineKit sharedEngineKit] startVideoPreview];
  113. }
  114. WFCCUserInfo *user = [[WFCCIMService sharedWFCIMService] getUserInfo:self.currentSession.participantIds[0] inGroup:self.currentSession.conversation.type == Group_Type ? self.currentSession.conversation.target : nil refresh:NO];
  115. self.portraitView = [[UIImageView alloc] init];
  116. [self.portraitView sd_setImageWithURL:[NSURL URLWithString:[user.portrait stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]] placeholderImage:[WFCUImage imageNamed:@"PersonalChat"]];
  117. self.portraitView.layer.masksToBounds = YES;
  118. self.portraitView.layer.cornerRadius = 10.f;
  119. self.portraitView.layer.borderColor = [UIColor whiteColor].CGColor;
  120. self.portraitView.layer.borderWidth = 1.0;
  121. [self.view addSubview:self.portraitView];
  122. self.userNameLabel = [[UILabel alloc] init];
  123. self.userNameLabel.font = [UIFont pingFangSCWithWeight:FontWeightStyleMedium size:27];
  124. self.userNameLabel.text = user.displayName;
  125. self.userNameLabel.textColor = [UIColor colorWithHexString:@"0xffffff"];
  126. [self.view addSubview:self.userNameLabel];
  127. if([WFCCUtilities isExternalTarget:self.currentSession.participantIds[0]]) {
  128. NSString *domainId = [WFCCUtilities getExternalDomain:self.currentSession.participantIds[0]];
  129. self.userNameLabel.attributedText = [WFCCUtilities getExternal:domainId withName:self.userNameLabel.text withColor:[WFCUConfigManager globalManager].externalNameColor withSize:24];
  130. }
  131. self.stateLabel = [[UILabel alloc] init];
  132. self.stateLabel.font = [UIFont pingFangSCWithWeight:FontWeightStyleRegular size:14];
  133. self.stateLabel.textColor = [UIColor colorWithHexString:@"0xB4B4B6"];
  134. [self.view addSubview:self.stateLabel];
  135. [self updateTopViewFrame];
  136. [self didChangeState:self.currentSession.state];//update ui
  137. [[NSNotificationCenter defaultCenter] addObserver:self
  138. selector:@selector(onDeviceOrientationDidChange)
  139. name:UIDeviceOrientationDidChangeNotification
  140. object:nil];
  141. [self onDeviceOrientationDidChange];
  142. }
  143. - (UIButton *)hangupButton {
  144. if (!_hangupButton) {
  145. _hangupButton = [[UIButton alloc] init];
  146. [_hangupButton setImage:[WFCUImage imageNamed:@"hangup"] forState:UIControlStateNormal];
  147. [_hangupButton setImage:[WFCUImage imageNamed:@"hangup_hover"] forState:UIControlStateHighlighted];
  148. [_hangupButton setImage:[WFCUImage imageNamed:@"hangup_hover"] forState:UIControlStateSelected];
  149. _hangupButton.backgroundColor = [UIColor clearColor];
  150. [_hangupButton addTarget:self action:@selector(hanupButtonDidTap:) forControlEvents:UIControlEventTouchDown];
  151. _hangupButton.hidden = YES;
  152. [self.view addSubview:_hangupButton];
  153. }
  154. return _hangupButton;
  155. }
  156. - (UIButton *)answerButton {
  157. if (!_answerButton) {
  158. _answerButton = [[UIButton alloc] init];
  159. if (self.currentSession.audioOnly) {
  160. [_answerButton setImage:[WFCUImage imageNamed:@"answer"] forState:UIControlStateNormal];
  161. [_answerButton setImage:[WFCUImage imageNamed:@"answer_hover"] forState:UIControlStateHighlighted];
  162. [_answerButton setImage:[WFCUImage imageNamed:@"answer_hover"] forState:UIControlStateSelected];
  163. } else {
  164. [_answerButton setImage:[WFCUImage imageNamed:@"video_answer"] forState:UIControlStateNormal];
  165. [_answerButton setImage:[WFCUImage imageNamed:@"video_answer_hover"] forState:UIControlStateHighlighted];
  166. [_answerButton setImage:[WFCUImage imageNamed:@"video_answer_hover"] forState:UIControlStateSelected];
  167. }
  168. _answerButton.backgroundColor = [UIColor clearColor];
  169. [_answerButton addTarget:self action:@selector(answerButtonDidTap:) forControlEvents:UIControlEventTouchDown];
  170. _answerButton.hidden = YES;
  171. [self.view addSubview:_answerButton];
  172. }
  173. return _answerButton;
  174. }
  175. - (UIButton *)minimizeButton {
  176. if (!_minimizeButton) {
  177. _minimizeButton = [[UIButton alloc] initWithFrame:CGRectMake(16, 32, 30, 30)];
  178. [_minimizeButton setImage:[WFCUImage imageNamed:@"minimize"] forState:UIControlStateNormal];
  179. [_minimizeButton setImage:[WFCUImage imageNamed:@"minimize_hover"] forState:UIControlStateHighlighted];
  180. [_minimizeButton setImage:[WFCUImage imageNamed:@"minimize_hover"] forState:UIControlStateSelected];
  181. _minimizeButton.backgroundColor = [UIColor clearColor];
  182. [_minimizeButton addTarget:self action:@selector(minimizeButtonDidTap:) forControlEvents:UIControlEventTouchDown];
  183. // _minimizeButton.hidden = YES;
  184. [self.view addSubview:_minimizeButton];
  185. }
  186. return _minimizeButton;
  187. }
  188. - (UIButton *)switchCameraButton {
  189. if (!_switchCameraButton) {
  190. _switchCameraButton = [[UIButton alloc] init];
  191. [_switchCameraButton setImage:[WFCUImage imageNamed:@"switchcamera"] forState:UIControlStateNormal];
  192. [_switchCameraButton setImage:[WFCUImage imageNamed:@"switchcamera_hover"] forState:UIControlStateHighlighted];
  193. [_switchCameraButton setImage:[WFCUImage imageNamed:@"switchcamera_hover"] forState:UIControlStateSelected];
  194. _switchCameraButton.backgroundColor = [UIColor clearColor];
  195. [_switchCameraButton addTarget:self action:@selector(switchCameraButtonDidTap:) forControlEvents:UIControlEventTouchDown];
  196. _switchCameraButton.hidden = YES;
  197. [self.view addSubview:_switchCameraButton];
  198. }
  199. return _switchCameraButton;
  200. }
  201. - (UIButton *)downgradeButton {
  202. if (!_downgradeButton) {
  203. _downgradeButton = [[UIButton alloc] init];
  204. [_downgradeButton setImage:[WFCUImage imageNamed:@"to_audio"] forState:UIControlStateNormal];
  205. [_downgradeButton setImage:[WFCUImage imageNamed:@"to_audio_hover"] forState:UIControlStateHighlighted];
  206. [_downgradeButton setImage:[WFCUImage imageNamed:@"to_audio_hover"] forState:UIControlStateSelected];
  207. _downgradeButton.backgroundColor = [UIColor clearColor];
  208. [_downgradeButton addTarget:self action:@selector(downgradeButtonDidTap:) forControlEvents:UIControlEventTouchDown];
  209. _downgradeButton.hidden = YES;
  210. [self.view addSubview:_downgradeButton];
  211. }
  212. return _downgradeButton;
  213. }
  214. - (UIButton *)audioButton {
  215. if (!_audioButton) {
  216. _audioButton = [[UIButton alloc] initWithFrame:CGRectMake(self.view.frame.size.width/2-ButtonSize/2, self.view.frame.size.height-10-ButtonSize, ButtonSize, ButtonSize)];
  217. [_audioButton setImage:[WFCUImage imageNamed:@"mute"] forState:UIControlStateNormal];
  218. [_audioButton setImage:[WFCUImage imageNamed:@"mute_hover"] forState:UIControlStateHighlighted];
  219. [_audioButton setImage:[WFCUImage imageNamed:@"mute_hover"] forState:UIControlStateSelected];
  220. _audioButton.backgroundColor = [UIColor clearColor];
  221. [_audioButton addTarget:self action:@selector(audioButtonDidTap:) forControlEvents:UIControlEventTouchDown];
  222. _audioButton.hidden = YES;
  223. [self updateAudioButton];
  224. [self.view addSubview:_audioButton];
  225. }
  226. return _audioButton;
  227. }
  228. - (UIButton *)speakerButton {
  229. if (!_speakerButton) {
  230. _speakerButton = [[UIButton alloc] initWithFrame:CGRectMake(self.view.frame.size.width/2-ButtonSize/2, self.view.frame.size.height-10-ButtonSize, ButtonSize, ButtonSize)];
  231. [_speakerButton setImage:[WFCUImage imageNamed:@"speaker"] forState:UIControlStateNormal];
  232. [_speakerButton setImage:[WFCUImage imageNamed:@"speaker_hover"] forState:UIControlStateHighlighted];
  233. [_speakerButton setImage:[WFCUImage imageNamed:@"speaker_hover"] forState:UIControlStateSelected];
  234. _speakerButton.backgroundColor = [UIColor clearColor];
  235. [_speakerButton addTarget:self action:@selector(speakerButtonDidTap:) forControlEvents:UIControlEventTouchDown];
  236. _speakerButton.hidden = YES;
  237. [self.view addSubview:_speakerButton];
  238. }
  239. return _speakerButton;
  240. }
  241. - (UIButton *)videoButton {
  242. if (!_videoButton) {
  243. _videoButton = [[UIButton alloc] initWithFrame:CGRectMake(self.view.frame.size.width/2-ButtonSize/2, self.view.frame.size.height-10-ButtonSize, ButtonSize, ButtonSize)];
  244. [_videoButton setTitle:WFCString(@"Video") forState:UIControlStateNormal];
  245. _videoButton.backgroundColor = [UIColor greenColor];
  246. [_videoButton addTarget:self action:@selector(videoButtonDidTap:) forControlEvents:UIControlEventTouchDown];
  247. _videoButton.hidden = YES;
  248. [self.view addSubview:_videoButton];
  249. }
  250. return _videoButton;
  251. }
  252. - (UIButton *)scalingButton {
  253. if (!_scalingButton) {
  254. _scalingButton = [[UIButton alloc] initWithFrame:CGRectMake(self.view.frame.size.width/2-ButtonSize/2, self.view.frame.size.height-10-ButtonSize, ButtonSize, ButtonSize)];
  255. [_scalingButton setTitle:WFCString(@"Scale") forState:UIControlStateNormal];
  256. _scalingButton.backgroundColor = [UIColor greenColor];
  257. [_scalingButton addTarget:self action:@selector(scalingButtonDidTap:) forControlEvents:UIControlEventTouchDown];
  258. _scalingButton.hidden = YES;
  259. [self.view addSubview:_scalingButton];
  260. }
  261. return _scalingButton;
  262. }
  263. - (void)setSwapVideoView:(BOOL)swapVideoView {
  264. _swapVideoView = swapVideoView;
  265. if (self.currentSession.state == kWFAVEngineStateIdle) {
  266. return;
  267. }
  268. if (swapVideoView || self.currentSession.state == kWFAVEngineStateOutgoing) {
  269. [self.currentSession setupLocalVideoView:self.bigVideoView scalingType:self.scalingType];
  270. [self.currentSession setupRemoteVideoView:self.smallVideoView scalingType:self.scalingType forUser:self.currentSession.participantIds[0] screenSharing:NO];
  271. } else {
  272. [self.currentSession setupLocalVideoView:self.smallVideoView scalingType:self.scalingType];
  273. [self.currentSession setupRemoteVideoView:self.bigVideoView scalingType:self.scalingType forUser:self.currentSession.participantIds[0] screenSharing:NO];
  274. }
  275. }
  276. - (void)startConnectedTimer {
  277. [self stopConnectedTimer];
  278. self.connectedTimer = [NSTimer scheduledTimerWithTimeInterval:1
  279. target:self
  280. selector:@selector(updateConnectedTimeLabel)
  281. userInfo:nil
  282. repeats:YES];
  283. [self.connectedTimer fire];
  284. }
  285. - (void)stopConnectedTimer {
  286. if (self.connectedTimer) {
  287. [self.connectedTimer invalidate];
  288. self.connectedTimer = nil;
  289. }
  290. }
  291. - (void)updateConnectedTimeLabel {
  292. long sec = [[NSDate date] timeIntervalSince1970] - self.currentSession.connectedTime / 1000;
  293. if (sec < 60 * 60) {
  294. self.stateLabel.text = [NSString stringWithFormat:@"%02ld:%02ld", sec / 60, sec % 60];
  295. } else {
  296. self.stateLabel.text = [NSString stringWithFormat:@"%02ld:%02ld:%02ld", sec / 60 / 60, (sec / 60) % 60, sec % 60];
  297. }
  298. }
  299. - (void)hanupButtonDidTap:(UIButton *)button {
  300. if(self.currentSession.state != kWFAVEngineStateIdle) {
  301. [self.currentSession endCall];
  302. }
  303. }
  304. - (void)answerButtonDidTap:(UIButton *)button {
  305. [WFCUUtilities checkRecordOrCameraPermission:YES complete:^(BOOL granted) {
  306. if(granted) {
  307. if(self.currentSession.audioOnly) {
  308. if (self.currentSession.state == kWFAVEngineStateIncomming) {
  309. [self.currentSession answerCall:NO callExtra:nil];
  310. }
  311. } else {
  312. [WFCUUtilities checkRecordOrCameraPermission:NO complete:^(BOOL granted) {
  313. if(granted) {
  314. if (self.currentSession.state == kWFAVEngineStateIncomming) {
  315. [self.currentSession answerCall:NO callExtra:nil];
  316. }
  317. }
  318. } viewController:self];
  319. }
  320. }
  321. } viewController:self];
  322. }
  323. - (void)minimizeButtonDidTap:(UIButton *)button {
  324. [WFCUFloatingWindow startCallFloatingWindow:self.currentSession focusUser:self.currentSession.participantIds[0] withTouchedBlock:^(WFAVCallSession *callSession, WFZConferenceInfo *conferenceInfo) {
  325. [[WFAVEngineKit sharedEngineKit] presentViewController:[[WFCUVideoViewController alloc] initWithSession:callSession]];
  326. }];
  327. [[WFAVEngineKit sharedEngineKit] dismissViewController:self];
  328. }
  329. - (void)switchCameraButtonDidTap:(UIButton *)button {
  330. if (self.currentSession.state != kWFAVEngineStateIdle) {
  331. [self.currentSession switchCamera];
  332. }
  333. }
  334. - (void)downgradeButtonDidTap:(UIButton *)button {
  335. if (self.currentSession.state == kWFAVEngineStateIncomming) {
  336. [WFCUUtilities checkRecordOrCameraPermission:YES complete:^(BOOL granted) {
  337. if(granted) {
  338. if (self.currentSession.state == kWFAVEngineStateIncomming) {
  339. [self.currentSession answerCall:YES callExtra:nil];
  340. }
  341. }
  342. } viewController:self];
  343. } else if(self.currentSession.state == kWFAVEngineStateConnected) {
  344. self.currentSession.audioOnly = !self.currentSession.isAudioOnly;
  345. }
  346. }
  347. - (void)audioButtonDidTap:(UIButton *)button {
  348. if (self.currentSession.state != kWFAVEngineStateIdle) {
  349. [self.currentSession muteAudio:!self.currentSession.audioMuted];
  350. [self updateAudioButton];
  351. }
  352. }
  353. - (void)updateAudioButton {
  354. if (self.currentSession.audioMuted) {
  355. [self.audioButton setImage:[WFCUImage imageNamed:@"mute_hover"] forState:UIControlStateNormal];
  356. } else {
  357. [self.audioButton setImage:[WFCUImage imageNamed:@"mute"] forState:UIControlStateNormal];
  358. }
  359. }
  360. - (void)speakerButtonDidTap:(UIButton *)button {
  361. if (self.currentSession.state != kWFAVEngineStateIdle) {
  362. [self.currentSession enableSpeaker:!self.currentSession.isSpeaker];
  363. [self updateSpeakerButton];
  364. }
  365. }
  366. - (void)updateSpeakerButton {
  367. if (!self.currentSession.isSpeaker) {
  368. if([self.currentSession isHeadsetPluggedIn]) {
  369. [self.speakerButton setImage:[WFCUImage imageNamed:@"speaker_headset"] forState:UIControlStateNormal];
  370. } else if([self.currentSession isBluetoothSpeaker]) {
  371. [self.speakerButton setImage:[WFCUImage imageNamed:@"speaker_bluetooth"] forState:UIControlStateNormal];
  372. } else {
  373. [self.speakerButton setImage:[WFCUImage imageNamed:@"speaker"] forState:UIControlStateNormal];
  374. }
  375. } else {
  376. [self.speakerButton setImage:[WFCUImage imageNamed:@"speaker_hover"] forState:UIControlStateNormal];
  377. }
  378. }
  379. - (void)viewWillAppear:(BOOL)animated {
  380. [super viewWillAppear:animated];
  381. if (_currentSession.state == kWFAVEngineStateConnected) {
  382. [self updateConnectedTimeLabel];
  383. [self startConnectedTimer];
  384. }
  385. }
  386. - (void)viewWillDisappear:(BOOL)animated {
  387. [super viewWillDisappear:animated];
  388. [self stopConnectedTimer];
  389. }
  390. - (void)setPanStartPoint:(CGPoint)panStartPoint {
  391. _panStartPoint = panStartPoint;
  392. _panStartVideoFrame = self.smallVideoView.frame;
  393. }
  394. - (void)moveToPanPoint:(CGPoint)panPoint {
  395. CGRect frame = self.panStartVideoFrame;
  396. CGSize moveSize = CGSizeMake(panPoint.x - self.panStartPoint.x, panPoint.y - self.panStartPoint.y);
  397. frame.origin.x += moveSize.width;
  398. frame.origin.y += moveSize.height;
  399. self.smallVideoView.frame = frame;
  400. }
  401. - (void)onSmallVideoPan:(UIPanGestureRecognizer *)recognize {
  402. switch (recognize.state) {
  403. case UIGestureRecognizerStateBegan:
  404. self.panStartPoint = [recognize translationInView:self.view];
  405. break;
  406. case UIGestureRecognizerStateChanged: {
  407. CGPoint currentPoint = [recognize translationInView:self.view];
  408. [self moveToPanPoint:currentPoint];
  409. break;
  410. }
  411. case UIGestureRecognizerStateEnded: {
  412. CGPoint endPoint = [recognize translationInView:self.view];
  413. [self moveToPanPoint:endPoint];
  414. break;
  415. }
  416. case UIGestureRecognizerStateCancelled:
  417. case UIGestureRecognizerStateFailed:
  418. default:
  419. break;
  420. }
  421. }
  422. - (void)onSmallVideoTaped:(id)sender {
  423. if (self.currentSession.state == kWFAVEngineStateConnected) {
  424. self.swapVideoView = !_swapVideoView;
  425. }
  426. }
  427. - (void)videoButtonDidTap:(UIButton *)button {
  428. if (self.currentSession.state != kWFAVEngineStateIdle) {
  429. [self.currentSession muteVideo:!self.currentSession.isVideoMuted];
  430. }
  431. }
  432. - (void)scalingButtonDidTap:(UIButton *)button {
  433. if (self.currentSession.state != kWFAVEngineStateIdle) {
  434. if (self.scalingType < kWFAVVideoScalingTypeAspectBalanced) {
  435. self.scalingType++;
  436. } else {
  437. self.scalingType = kWFAVVideoScalingTypeAspectFit;
  438. }
  439. self.swapVideoView = _swapVideoView;
  440. }
  441. }
  442. - (CGRect)getButtomCenterButtonFrame {
  443. return CGRectMake(self.view.frame.size.width/2-ButtonSize/2, self.view.frame.size.height-45-ButtonSize, ButtonSize, ButtonSize);
  444. }
  445. - (CGRect)getButtomLeftButtonFrame {
  446. return CGRectMake(self.view.frame.size.width/4-ButtonSize/2, self.view.frame.size.height-45-ButtonSize, ButtonSize, ButtonSize);
  447. }
  448. - (CGRect)getButtomRightButtonFrame {
  449. return CGRectMake(self.view.frame.size.width*3/4-ButtonSize/2, self.view.frame.size.height-45-ButtonSize, ButtonSize, ButtonSize);
  450. }
  451. - (CGRect)getToAudioButtonFrame {
  452. return CGRectMake(self.view.frame.size.width*3/4-ButtonSize/2, self.view.frame.size.height-45-ButtonSize-ButtonSize-2, ButtonSize, ButtonSize);
  453. }
  454. - (void)updateTopViewFrame {
  455. CGFloat containerWidth = self.view.bounds.size.width;
  456. CGFloat containerHeight = self.view.bounds.size.height;
  457. if (self.currentSession.isAudioOnly) {
  458. CGFloat postionY = (containerHeight - 110) / 2.0 - 70;
  459. self.portraitView.frame = CGRectMake((containerWidth-110)/2, postionY, 110, 110);;
  460. postionY += 110 + 16;
  461. self.userNameLabel.frame = CGRectMake((containerWidth - 240)/2, postionY, 240, 27);
  462. self.userNameLabel.textAlignment = NSTextAlignmentCenter;
  463. postionY += 12 + 27;
  464. self.stateLabel.frame = CGRectMake((containerWidth - 240)/2, postionY, 240, 26);
  465. self.stateLabel.textAlignment = NSTextAlignmentCenter;
  466. } else {
  467. CGFloat postionX = 16;
  468. self.portraitView.frame = CGRectMake(postionX, [WFCUUtilities wf_navigationFullHeight], 62, 62);
  469. postionX += 62;
  470. postionX += 8;
  471. self.userNameLabel.frame = CGRectMake(postionX, [WFCUUtilities wf_navigationFullHeight] + 8, 240, 26);
  472. self.userNameLabel.textAlignment = NSTextAlignmentLeft;
  473. if(![NSThread isMainThread]) {
  474. NSLog(@"error not main thread");
  475. }
  476. if(self.currentSession.state == kWFAVEngineStateConnected) {
  477. self.stateLabel.frame = CGRectMake(54, 36, 240, 20);
  478. } else {
  479. self.stateLabel.frame = CGRectMake(88, [WFCUUtilities wf_navigationFullHeight] + 26 + 14, 240, 16);
  480. }
  481. // self.stateLabel.hidden = YES;
  482. self.stateLabel.textAlignment = NSTextAlignmentLeft;
  483. }
  484. }
  485. - (void)onClickedBigVideoView:(id)sender {
  486. if (self.currentSession.state != kWFAVEngineStateConnected) {
  487. return;
  488. }
  489. if (self.currentSession.audioOnly) {
  490. return;
  491. }
  492. if (self.smallVideoView.hidden) {
  493. if (self.hangupButton.hidden) {
  494. self.hangupButton.hidden = NO;
  495. self.audioButton.hidden = NO;
  496. self.switchCameraButton.hidden = NO;
  497. self.smallVideoView.hidden = NO;
  498. self.minimizeButton.hidden = NO;
  499. self.downgradeButton.hidden = NO;
  500. } else {
  501. self.hangupButton.hidden = YES;
  502. self.audioButton.hidden = YES;
  503. self.downgradeButton.hidden = YES;
  504. self.switchCameraButton.hidden = YES;
  505. self.minimizeButton.hidden = YES;
  506. }
  507. } else {
  508. self.smallVideoView.hidden = YES;
  509. }
  510. }
  511. #pragma mark - WFAVEngineDelegate
  512. - (void)didChangeState:(WFAVEngineState)state {
  513. if (!self.viewLoaded) {
  514. return;
  515. }
  516. switch (state) {
  517. case kWFAVEngineStateIdle:
  518. self.answerButton.hidden = YES;
  519. self.hangupButton.hidden = YES;
  520. self.switchCameraButton.hidden = YES;
  521. self.audioButton.hidden = YES;
  522. self.videoButton.hidden = YES;
  523. self.scalingButton.hidden = YES;
  524. [self stopConnectedTimer];
  525. self.userNameLabel.hidden = NO;
  526. self.portraitView.hidden = NO;
  527. self.stateLabel.text = WFCString(@"CallEnded");
  528. self.smallVideoView.hidden = YES;
  529. self.bigVideoView.hidden = YES;
  530. self.minimizeButton.hidden = YES;
  531. self.speakerButton.hidden = YES;
  532. self.downgradeButton.hidden = YES;
  533. [self updateTopViewFrame];
  534. break;
  535. case kWFAVEngineStateOutgoing:
  536. self.answerButton.hidden = YES;
  537. self.hangupButton.hidden = NO;
  538. self.hangupButton.frame = [self getButtomCenterButtonFrame];
  539. self.audioButton.frame = [self getButtomLeftButtonFrame];
  540. if (self.currentSession.isAudioOnly) {
  541. [self updateSpeakerButton];
  542. dispatch_async(dispatch_get_main_queue(), ^{
  543. [self updateSpeakerButton];
  544. });
  545. self.speakerButton.frame = [self getButtomRightButtonFrame];
  546. self.speakerButton.hidden = NO;
  547. self.switchCameraButton.hidden = YES;
  548. } else {
  549. self.speakerButton.hidden = YES;
  550. self.switchCameraButton.frame = [self getButtomRightButtonFrame];
  551. self.switchCameraButton.hidden = NO;
  552. }
  553. self.audioButton.hidden = NO;
  554. self.videoButton.hidden = YES;
  555. self.scalingButton.hidden = YES;
  556. [self.currentSession setupLocalVideoView:self.bigVideoView scalingType:self.scalingType];
  557. [self.currentSession setupRemoteVideoView:nil scalingType:self.scalingType forUser:self.currentSession.participantIds[0] screenSharing:NO];
  558. self.stateLabel.text = WFCString(@"WaitingAccept");
  559. self.smallVideoView.hidden = YES;
  560. self.userNameLabel.hidden = NO;
  561. self.portraitView.hidden = NO;
  562. self.minimizeButton.hidden = NO;
  563. [self updateTopViewFrame];
  564. break;
  565. case kWFAVEngineStateConnecting:
  566. self.answerButton.hidden = YES;
  567. self.hangupButton.hidden = NO;
  568. self.speakerButton.hidden = YES;
  569. self.hangupButton.frame = [self getButtomCenterButtonFrame];
  570. self.audioButton.frame = [self getButtomLeftButtonFrame];
  571. self.switchCameraButton.hidden = YES;
  572. self.audioButton.hidden = NO;
  573. self.audioButton.enabled = NO;
  574. if (self.currentSession.isAudioOnly) {
  575. self.speakerButton.hidden = NO;
  576. self.speakerButton.enabled = NO;
  577. self.speakerButton.frame = [self getButtomRightButtonFrame];
  578. } else {
  579. self.switchCameraButton.hidden = NO;
  580. self.switchCameraButton.enabled = NO;
  581. self.switchCameraButton.frame = [self getButtomRightButtonFrame];
  582. }
  583. self.videoButton.hidden = YES;
  584. self.scalingButton.hidden = YES;
  585. self.swapVideoView = NO;
  586. self.stateLabel.text = WFCString(@"CallConnecting");
  587. self.smallVideoView.hidden = NO;
  588. self.downgradeButton.hidden = YES;
  589. break;
  590. case kWFAVEngineStateConnected:
  591. self.answerButton.hidden = YES;
  592. self.hangupButton.hidden = NO;
  593. self.hangupButton.frame = [self getButtomCenterButtonFrame];
  594. self.audioButton.hidden = NO;
  595. self.audioButton.enabled = YES;
  596. if (self.currentSession.isAudioOnly) {
  597. self.speakerButton.hidden = NO;
  598. self.speakerButton.enabled = YES;
  599. self.speakerButton.frame = [self getButtomRightButtonFrame];
  600. [self updateSpeakerButton];
  601. self.audioButton.frame = [self getButtomLeftButtonFrame];
  602. self.switchCameraButton.hidden = YES;
  603. } else {
  604. self.speakerButton.hidden = YES;
  605. if(self.currentSession.isHeadsetPluggedIn || self.currentSession.isBluetoothSpeaker) {
  606. [self.currentSession enableSpeaker:NO];
  607. } else {
  608. [self.currentSession enableSpeaker:YES];
  609. }
  610. self.audioButton.frame = [self getButtomLeftButtonFrame];
  611. self.switchCameraButton.hidden = NO;
  612. self.switchCameraButton.enabled = YES;
  613. self.switchCameraButton.frame = [self getButtomRightButtonFrame];
  614. }
  615. self.videoButton.hidden = YES;
  616. self.scalingButton.hidden = YES;
  617. self.minimizeButton.hidden = NO;
  618. if (self.currentSession.isAudioOnly) {
  619. self.downgradeButton.hidden = YES;;
  620. } else {
  621. self.downgradeButton.hidden = NO;
  622. self.downgradeButton.frame = [self getToAudioButtonFrame];
  623. }
  624. if (self.currentSession.isAudioOnly) {
  625. [self.currentSession setupLocalVideoView:nil scalingType:self.scalingType];
  626. if(self.currentSession.participantIds.count > 0) {
  627. [self.currentSession setupRemoteVideoView:nil scalingType:self.scalingType forUser:self.currentSession.participantIds[0] screenSharing:NO];
  628. }
  629. self.smallVideoView.hidden = YES;
  630. self.bigVideoView.hidden = YES;
  631. [_downgradeButton setImage:[WFCUImage imageNamed:@"to_video"] forState:UIControlStateNormal];
  632. [_downgradeButton setImage:[WFCUImage imageNamed:@"to_video_hover"] forState:UIControlStateHighlighted];
  633. [_downgradeButton setImage:[WFCUImage imageNamed:@"to_video_hover"] forState:UIControlStateSelected];
  634. } else {
  635. if(self.currentSession.participantIds.count > 0) {
  636. [self.currentSession setupLocalVideoView:self.smallVideoView scalingType:self.scalingType];
  637. [self.currentSession setupRemoteVideoView:self.bigVideoView scalingType:self.scalingType forUser:self.currentSession.participantIds[0] screenSharing:NO];
  638. }
  639. self.smallVideoView.hidden = NO;
  640. self.bigVideoView.hidden = NO;
  641. [_downgradeButton setImage:[WFCUImage imageNamed:@"to_audio"] forState:UIControlStateNormal];
  642. [_downgradeButton setImage:[WFCUImage imageNamed:@"to_audio_hover"] forState:UIControlStateHighlighted];
  643. [_downgradeButton setImage:[WFCUImage imageNamed:@"to_audio_hover"] forState:UIControlStateSelected];
  644. }
  645. if (!_currentSession.isAudioOnly) {
  646. self.userNameLabel.hidden = YES;
  647. self.portraitView.hidden = YES;
  648. } else {
  649. self.userNameLabel.hidden = NO;
  650. self.portraitView.hidden = NO;
  651. }
  652. [self updateConnectedTimeLabel];
  653. [self startConnectedTimer];
  654. [self updateTopViewFrame];
  655. break;
  656. case kWFAVEngineStateIncomming:
  657. self.answerButton.hidden = NO;
  658. self.answerButton.frame = [self getButtomRightButtonFrame];
  659. self.hangupButton.hidden = NO;
  660. self.hangupButton.frame = [self getButtomLeftButtonFrame];
  661. self.switchCameraButton.hidden = YES;
  662. self.audioButton.hidden = YES;
  663. self.videoButton.hidden = YES;
  664. self.scalingButton.hidden = YES;
  665. self.downgradeButton.hidden = NO;
  666. self.downgradeButton.frame = [self getToAudioButtonFrame];
  667. [self.currentSession setupLocalVideoView:self.bigVideoView scalingType:self.scalingType];
  668. [self.currentSession setupRemoteVideoView:nil scalingType:self.scalingType forUser:self.currentSession.participantIds[0] screenSharing:NO];
  669. self.stateLabel.text = WFCString(@"InvitingYou");
  670. self.smallVideoView.hidden = YES;
  671. if (self.currentSession.isAudioOnly) {
  672. self.downgradeButton.hidden = YES;;
  673. } else {
  674. self.downgradeButton.hidden = NO;
  675. self.downgradeButton.frame = [self getToAudioButtonFrame];
  676. }
  677. self.minimizeButton.hidden = NO;
  678. break;
  679. default:
  680. break;
  681. }
  682. }
  683. - (void)didCreateLocalVideoTrack:(RTCVideoTrack *)localVideoTrack {
  684. }
  685. - (void)didReceiveRemoteVideoTrack:(RTCVideoTrack *)remoteVideoTrack fromUser:(NSString *)userId screenSharing:(BOOL)screenSharing {
  686. }
  687. - (void)didVideoMuted:(BOOL)videoMuted fromUser:(NSString *)userId {
  688. }
  689. - (void)didReportAudioVolume:(NSInteger)volume ofUser:(NSString *)userId {
  690. }
  691. - (void)didCallEndWithReason:(WFAVCallEndReason)reason {
  692. if(reason == kWFAVCallEndReasonBusy) {
  693. [self.view makeToast:@"忙线未接听!" duration:3 position:CSToastPositionCenter];
  694. } else if(reason == kWFAVCallEndReasonInterrupted) {
  695. [self.view makeToast:@"通话中断!" duration:3 position:CSToastPositionCenter];
  696. } else if(reason == kWFAVCallEndReasonRemoteInterrupted) {
  697. [self.view makeToast:@"对方通话中断!" duration:3 position:CSToastPositionCenter];
  698. }
  699. dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
  700. [[WFAVEngineKit sharedEngineKit] dismissViewController:self];
  701. });
  702. }
  703. - (void)didParticipantJoined:(NSString *)userId screenSharing:(BOOL)screenSharing {
  704. }
  705. - (void)didParticipantConnected:(NSString *)userId screenSharing:(BOOL)screenSharing {
  706. }
  707. - (void)didParticipantLeft:(NSString *)userId screenSharing:(BOOL)screenSharing withReason:(WFAVCallEndReason)reason {
  708. }
  709. - (void)didChangeMode:(BOOL)isAudioOnly {
  710. [self didChangeState:self.currentSession.state];
  711. }
  712. - (void)didError:(NSError *)error {
  713. }
  714. - (void)didGetStats:(NSArray *)stats {
  715. }
  716. - (void)didChangeAudioRoute {
  717. [self updateSpeakerButton];
  718. }
  719. - (void)didMedia:(NSString *_Nullable)media lostPackage:(int)lostPackage screenSharing:(BOOL)screenSharing {
  720. //发送方丢包超过6为网络不好
  721. if(lostPackage > 6) {
  722. [self.view makeToast:@"您的网络不好" duration:3 position:CSToastPositionCenter];
  723. }
  724. }
  725. - (void)didMedia:(NSString *)media lostPackage:(int)lostPackage uplink:(BOOL)uplink ofUser:(NSString *)userId screenSharing:(BOOL)screenSharing {
  726. //如果uplink ture对方网络不好,false您的网络不好
  727. //接受方丢包超过10为网络不好
  728. if(lostPackage > 10) {
  729. if(uplink) {
  730. NSLog(@"对方的网络不好");
  731. [self.view makeToast:@"对方的网络不好" duration:3 position:CSToastPositionCenter];
  732. } else {
  733. NSLog(@"您的网络不好");
  734. [self.view makeToast:@"您的网络不好" duration:3 position:CSToastPositionCenter];
  735. }
  736. }
  737. }
  738. //1.决定当前界面是否开启自动转屏,如果返回NO,后面两个方法也不会被调用,只是会支持默认的方向
  739. - (BOOL)shouldAutorotate {
  740. return YES;
  741. }
  742. //2.返回支持的旋转方向
  743. //iPad设备上,默认返回值UIInterfaceOrientationMaskAllButUpSideDwon
  744. //iPad设备上,默认返回值是UIInterfaceOrientationMaskAll
  745. - (UIInterfaceOrientationMask)supportedInterfaceOrientations{
  746. return UIDeviceOrientationLandscapeLeft | UIDeviceOrientationLandscapeRight | UIDeviceOrientationPortrait;
  747. }
  748. //3.返回进入界面默认显示方向
  749. - (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation {
  750. return UIInterfaceOrientationPortrait;
  751. }
  752. - (BOOL)onDeviceOrientationDidChange{
  753. if (self.currentSession.state == kWFAVEngineStateIdle) {
  754. return YES;
  755. }
  756. //获取当前设备Device
  757. UIDevice *device = [UIDevice currentDevice] ;
  758. //识别当前设备的旋转方向
  759. CGRect smallVideoFrame = CGRectZero;
  760. CGFloat width = self.view.bounds.size.width;
  761. CGFloat height = self.view.bounds.size.height;
  762. switch (device.orientation) {
  763. case UIDeviceOrientationFaceUp:
  764. break;
  765. case UIDeviceOrientationFaceDown:
  766. break;
  767. case UIDeviceOrientationUnknown:
  768. //系统当前无法识别设备朝向,可能是倾斜
  769. break;
  770. case UIDeviceOrientationLandscapeLeft:
  771. self.smallVideoView.transform = CGAffineTransformMakeRotation(M_PI_2);
  772. self.bigVideoView.transform = CGAffineTransformMakeRotation(M_PI_2);
  773. self.bigVideoView.frame = self.view.bounds;
  774. smallVideoFrame = CGRectMake(width - SmallVideoView - 8, height - 8 - [WFCUUtilities wf_navigationFullHeight] + 64 - SmallVideoView - SmallVideoView/3 - [WFCUUtilities wf_safeDistanceBottom], SmallVideoView * 4 /3, SmallVideoView);
  775. self.smallVideoView.frame = smallVideoFrame;
  776. self.swapVideoView = _swapVideoView;
  777. break;
  778. case UIDeviceOrientationLandscapeRight:
  779. self.smallVideoView.transform = CGAffineTransformMakeRotation(-M_PI_2);
  780. self.bigVideoView.transform = CGAffineTransformMakeRotation(-M_PI_2);
  781. self.bigVideoView.frame = self.view.bounds;
  782. smallVideoFrame = CGRectMake(8-SmallVideoView/3, 8 + [WFCUUtilities wf_navigationFullHeight] - 64+SmallVideoView/3, SmallVideoView * 4 /3, SmallVideoView);
  783. self.smallVideoView.frame = smallVideoFrame;
  784. self.swapVideoView = _swapVideoView;
  785. break;
  786. case UIDeviceOrientationPortrait:
  787. self.smallVideoView.transform = CGAffineTransformMakeRotation(0);
  788. self.bigVideoView.transform = CGAffineTransformMakeRotation(0);
  789. self.bigVideoView.frame = self.view.bounds;
  790. smallVideoFrame = CGRectMake(self.view.frame.size.width - SmallVideoView, [WFCUUtilities wf_navigationFullHeight], SmallVideoView, SmallVideoView * 4 /3);
  791. self.smallVideoView.frame = smallVideoFrame;
  792. self.swapVideoView = _swapVideoView;
  793. break;
  794. case UIDeviceOrientationPortraitUpsideDown:
  795. break;
  796. default:
  797. NSLog(@"無法识别");
  798. break;
  799. }
  800. return YES;
  801. }
  802. #endif
  803. @end