2
0

WFCUMultiVideoViewController.m 45 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076
  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 "WFCUMultiVideoViewController.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. #import "WFCUParticipantCollectionViewCell.h"
  16. #endif
  17. #import "SDWebImage.h"
  18. #import <WFChatClient/WFCCConversation.h>
  19. #import "WFCUPortraitCollectionViewCell.h"
  20. #import "WFCUParticipantCollectionViewLayout.h"
  21. #import "WFCUSeletedUserViewController.h"
  22. #import "UIView+Toast.h"
  23. @interface WFCUMultiVideoViewController () <UITextFieldDelegate
  24. #if WFCU_SUPPORT_VOIP
  25. ,WFAVCallSessionDelegate
  26. #endif
  27. ,UICollectionViewDataSource
  28. ,UICollectionViewDelegate
  29. >
  30. #if WFCU_SUPPORT_VOIP
  31. @property (nonatomic, strong) UIView *bigVideoView;
  32. @property (nonatomic, strong) UICollectionView *smallCollectionView;
  33. @property (nonatomic, strong) UICollectionView *portraitCollectionView;
  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 *videoButton;
  40. @property (nonatomic, strong) UIButton *scalingButton;
  41. @property (nonatomic, strong) UIButton *minimizeButton;
  42. @property (nonatomic, strong) UIButton *addParticipantButton;
  43. @property (nonatomic, strong) UIImageView *portraitView;
  44. @property (nonatomic, strong) UILabel *userNameLabel;
  45. @property (nonatomic, strong) UILabel *stateLabel;
  46. @property (nonatomic, strong) UILabel *connectTimeLabel;
  47. @property (nonatomic, strong) WFAVCallSession *currentSession;
  48. @property (nonatomic, assign) WFAVVideoScalingType smallScalingType;
  49. @property (nonatomic, assign) WFAVVideoScalingType bigScalingType;
  50. @property (nonatomic, assign) CGPoint panStartPoint;
  51. @property (nonatomic, assign) CGRect panStartVideoFrame;
  52. @property (nonatomic, strong) NSTimer *connectedTimer;
  53. @property (nonatomic, strong) NSMutableArray<NSString *> *participants;
  54. //视频时,大屏用户正在说话
  55. @property (nonatomic, strong)UIImageView *speakingView;
  56. #endif
  57. @end
  58. #define ButtonSize 60
  59. #define BottomPadding 36
  60. #define SmallVideoView 120
  61. #define OperationTitleFont 10
  62. #define OperationButtonSize 50
  63. #define PortraitItemSize 48
  64. #define PortraitLabelSize 16
  65. @implementation WFCUMultiVideoViewController
  66. #if !WFCU_SUPPORT_VOIP
  67. - (instancetype)initWithSession:(WFAVCallSession *)session {
  68. self = [super init];
  69. return self;
  70. }
  71. - (instancetype)initWithTargets:(NSArray<NSString *> *)targetIds conversation:(WFCCConversation *)conversation audioOnly:(BOOL)audioOnly {
  72. self = [super init];
  73. return self;
  74. }
  75. #else
  76. - (instancetype)initWithSession:(WFAVCallSession *)session {
  77. self = [super init];
  78. if (self) {
  79. self.currentSession = session;
  80. self.currentSession.delegate = self;
  81. [self didChangeState:kWFAVEngineStateIncomming];
  82. [self rearrangeParticipants];
  83. }
  84. return self;
  85. }
  86. - (instancetype)initWithTargets:(NSArray<NSString *> *)targetIds conversation:(WFCCConversation *)conversation audioOnly:(BOOL)audioOnly {
  87. self = [super init];
  88. if (self) {
  89. WFAVCallSession *session = [[WFAVEngineKit sharedEngineKit] startCall:targetIds
  90. audioOnly:audioOnly
  91. conversation:conversation
  92. sessionDelegate:self];
  93. self.currentSession = session;
  94. [self rearrangeParticipants];
  95. }
  96. return self;
  97. }
  98. /*
  99. session的participantIds是除了自己外的所有成员。这里把自己也加入列表,然后把发起者放到最后面。
  100. */
  101. - (void)rearrangeParticipants {
  102. self.participants = [[NSMutableArray alloc] init];
  103. [self.participants addObjectsFromArray:self.currentSession.participantIds];
  104. if ([self.currentSession.initiator isEqualToString:[WFCCNetworkService sharedInstance].userId]) {
  105. [self.participants addObject:[WFCCNetworkService sharedInstance].userId];
  106. } else {
  107. [self.participants insertObject:[WFCCNetworkService sharedInstance].userId atIndex:[self.participants indexOfObject:self.currentSession.initiator]];
  108. [self.participants removeObject:self.currentSession.initiator];
  109. [self.participants addObject:self.currentSession.initiator];
  110. }
  111. }
  112. - (void)viewDidLoad {
  113. [super viewDidLoad];
  114. [self.view setBackgroundColor:[UIColor blackColor]];
  115. self.smallScalingType = kWFAVVideoScalingTypeAspectFill;
  116. self.bigScalingType = kWFAVVideoScalingTypeAspectBalanced;
  117. self.bigVideoView = [[UIView alloc] initWithFrame:self.view.bounds];
  118. UITapGestureRecognizer *tapBigVideo = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(onClickedBigVideoView:)];
  119. [self.bigVideoView addGestureRecognizer:tapBigVideo];
  120. [self.view addSubview:self.bigVideoView];
  121. UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init];
  122. CGFloat itemWidth = (self.view.frame.size.width + layout.minimumLineSpacing)/3 - layout.minimumLineSpacing;
  123. layout.itemSize = CGSizeMake(itemWidth, itemWidth);
  124. layout.scrollDirection = UICollectionViewScrollDirectionHorizontal;
  125. self.smallCollectionView = [[UICollectionView alloc] initWithFrame:CGRectMake(0, kStatusBarAndNavigationBarHeight, self.view.frame.size.width, itemWidth) collectionViewLayout:layout];
  126. self.smallCollectionView.dataSource = self;
  127. self.smallCollectionView.delegate = self;
  128. [self.smallCollectionView registerClass:[WFCUParticipantCollectionViewCell class] forCellWithReuseIdentifier:@"cell"];
  129. self.smallCollectionView.backgroundColor = [UIColor clearColor];
  130. [self.smallCollectionView addGestureRecognizer:[[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(onSmallVideoPan:)]];
  131. if (self.currentSession.audioOnly) {
  132. self.smallCollectionView.hidden = YES;
  133. }
  134. [self.view addSubview:self.smallCollectionView];
  135. WFCUParticipantCollectionViewLayout *layout2 = [[WFCUParticipantCollectionViewLayout alloc] init];
  136. layout2.itemHeight = PortraitItemSize + PortraitLabelSize;
  137. layout2.itemWidth = PortraitItemSize;
  138. layout2.lineSpace = 6;
  139. layout2.itemSpace = 6;
  140. self.portraitCollectionView = [[UICollectionView alloc] initWithFrame:CGRectMake(16, self.view.frame.size.height - BottomPadding - ButtonSize - (PortraitItemSize + PortraitLabelSize)*3 - PortraitLabelSize, self.view.frame.size.width - 32, (PortraitItemSize + PortraitLabelSize)*3 + PortraitLabelSize) collectionViewLayout:layout2];
  141. self.portraitCollectionView.dataSource = self;
  142. self.portraitCollectionView.delegate = self;
  143. [self.portraitCollectionView registerClass:[WFCUPortraitCollectionViewCell class] forCellWithReuseIdentifier:@"cell2"];
  144. self.portraitCollectionView.backgroundColor = [UIColor clearColor];
  145. [self.view addSubview:self.portraitCollectionView];
  146. [self checkAVPermission];
  147. if(self.currentSession.state == kWFAVEngineStateOutgoing && !self.currentSession.isAudioOnly) {
  148. [[WFAVEngineKit sharedEngineKit] startPreview];
  149. }
  150. WFCCUserInfo *user = [[WFCCIMService sharedWFCIMService] getUserInfo:self.currentSession.initiator inGroup:self.currentSession.conversation.type == Group_Type ? self.currentSession.conversation.target : nil refresh:NO];
  151. self.portraitView = [[UIImageView alloc] init];
  152. [self.portraitView sd_setImageWithURL:[NSURL URLWithString:[user.portrait stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]] placeholderImage:[UIImage imageNamed:@"PersonalChat"]];
  153. self.portraitView.layer.masksToBounds = YES;
  154. self.portraitView.layer.cornerRadius = 8.f;
  155. [self.view addSubview:self.portraitView];
  156. self.userNameLabel = [[UILabel alloc] init];
  157. self.userNameLabel.font = [UIFont systemFontOfSize:26];
  158. self.userNameLabel.text = user.displayName;
  159. self.userNameLabel.textColor = [UIColor whiteColor];
  160. [self.view addSubview:self.userNameLabel];
  161. self.stateLabel = [[UILabel alloc] init];
  162. self.stateLabel.font = [UIFont systemFontOfSize:16];
  163. self.stateLabel.textColor = [UIColor whiteColor];
  164. [self.view addSubview:self.stateLabel];
  165. self.connectTimeLabel = [[UILabel alloc] init];
  166. self.connectTimeLabel.font = [UIFont systemFontOfSize:16];
  167. self.connectTimeLabel.textColor = [UIColor whiteColor];
  168. [self.view addSubview:self.connectTimeLabel];
  169. [self updateTopViewFrame];
  170. [self didChangeState:self.currentSession.state];//update ui
  171. }
  172. - (UIButton *)hangupButton {
  173. if (!_hangupButton) {
  174. _hangupButton = [[UIButton alloc] init];
  175. [_hangupButton setImage:[UIImage imageNamed:@"hangup"] forState:UIControlStateNormal];
  176. [_hangupButton setImage:[UIImage imageNamed:@"hangup_hover"] forState:UIControlStateHighlighted];
  177. [_hangupButton setImage:[UIImage imageNamed:@"hangup_hover"] forState:UIControlStateSelected];
  178. _hangupButton.backgroundColor = [UIColor clearColor];
  179. [_hangupButton addTarget:self action:@selector(hanupButtonDidTap:) forControlEvents:UIControlEventTouchDown];
  180. _hangupButton.hidden = YES;
  181. [self.view addSubview:_hangupButton];
  182. }
  183. return _hangupButton;
  184. }
  185. - (UIButton *)answerButton {
  186. if (!_answerButton) {
  187. _answerButton = [[UIButton alloc] init];
  188. [_answerButton setImage:[UIImage imageNamed:@"answer"] forState:UIControlStateNormal];
  189. [_answerButton setImage:[UIImage imageNamed:@"answer_hover"] forState:UIControlStateHighlighted];
  190. [_answerButton setImage:[UIImage imageNamed:@"answer_hover"] forState:UIControlStateSelected];
  191. _answerButton.backgroundColor = [UIColor clearColor];
  192. [_answerButton addTarget:self action:@selector(answerButtonDidTap:) forControlEvents:UIControlEventTouchDown];
  193. _answerButton.hidden = YES;
  194. [self.view addSubview:_answerButton];
  195. }
  196. return _answerButton;
  197. }
  198. - (UIButton *)minimizeButton {
  199. if (!_minimizeButton) {
  200. _minimizeButton = [[UIButton alloc] initWithFrame:CGRectMake(16, 26, 30, 30)];
  201. [_minimizeButton setImage:[UIImage imageNamed:@"minimize"] forState:UIControlStateNormal];
  202. [_minimizeButton setImage:[UIImage imageNamed:@"minimize_hover"] forState:UIControlStateHighlighted];
  203. [_minimizeButton setImage:[UIImage imageNamed:@"minimize_hover"] forState:UIControlStateSelected];
  204. _minimizeButton.backgroundColor = [UIColor clearColor];
  205. [_minimizeButton addTarget:self action:@selector(minimizeButtonDidTap:) forControlEvents:UIControlEventTouchDown];
  206. _minimizeButton.hidden = YES;
  207. [self.view addSubview:_minimizeButton];
  208. }
  209. return _minimizeButton;
  210. }
  211. - (UIButton *)addParticipantButton {
  212. if (!_addParticipantButton) {
  213. _addParticipantButton = [[UIButton alloc] initWithFrame:CGRectMake(self.view.frame.size.width - 16 - 30, 26, 30, 30)];
  214. [_addParticipantButton setImage:[UIImage imageNamed:@"plus-circle"] forState:UIControlStateNormal];
  215. [_addParticipantButton setImage:[UIImage imageNamed:@"plus-circle"] forState:UIControlStateHighlighted];
  216. [_addParticipantButton setImage:[UIImage imageNamed:@"plus-circle"] forState:UIControlStateSelected];
  217. _addParticipantButton.backgroundColor = [UIColor clearColor];
  218. [_addParticipantButton addTarget:self action:@selector(addParticipantButtonDidTap:) forControlEvents:UIControlEventTouchDown];
  219. _addParticipantButton.hidden = YES;
  220. [self.view addSubview:_addParticipantButton];
  221. }
  222. return _addParticipantButton;
  223. }
  224. - (UIButton *)switchCameraButton {
  225. if (!_switchCameraButton) {
  226. _switchCameraButton = [[UIButton alloc] init];
  227. [_switchCameraButton setImage:[UIImage imageNamed:@"switchcamera"] forState:UIControlStateNormal];
  228. [_switchCameraButton setImage:[UIImage imageNamed:@"switchcamera_hover"] forState:UIControlStateHighlighted];
  229. [_switchCameraButton setImage:[UIImage imageNamed:@"switchcamera_hover"] forState:UIControlStateSelected];
  230. _switchCameraButton.backgroundColor = [UIColor clearColor];
  231. [_switchCameraButton addTarget:self action:@selector(switchCameraButtonDidTap:) forControlEvents:UIControlEventTouchDown];
  232. _switchCameraButton.hidden = YES;
  233. [self.view addSubview:_switchCameraButton];
  234. }
  235. return _switchCameraButton;
  236. }
  237. - (UIButton *)audioButton {
  238. if (!_audioButton) {
  239. _audioButton = [[UIButton alloc] initWithFrame:CGRectMake(self.view.frame.size.width/2-ButtonSize/2, self.view.frame.size.height-10-ButtonSize, ButtonSize, ButtonSize)];
  240. [_audioButton setImage:[UIImage imageNamed:@"mute"] forState:UIControlStateNormal];
  241. [_audioButton setImage:[UIImage imageNamed:@"mute_hover"] forState:UIControlStateHighlighted];
  242. [_audioButton setImage:[UIImage imageNamed:@"mute_hover"] forState:UIControlStateSelected];
  243. _audioButton.backgroundColor = [UIColor clearColor];
  244. [_audioButton addTarget:self action:@selector(audioButtonDidTap:) forControlEvents:UIControlEventTouchDown];
  245. _audioButton.hidden = YES;
  246. [self updateAudioButton];
  247. [self.view addSubview:_audioButton];
  248. }
  249. return _audioButton;
  250. }
  251. - (UIButton *)speakerButton {
  252. if (!_speakerButton) {
  253. _speakerButton = [[UIButton alloc] initWithFrame:CGRectMake(self.view.frame.size.width/2-ButtonSize/2, self.view.frame.size.height-10-ButtonSize, ButtonSize, ButtonSize)];
  254. [_speakerButton setImage:[UIImage imageNamed:@"speaker"] forState:UIControlStateNormal];
  255. [_speakerButton setImage:[UIImage imageNamed:@"speaker_hover"] forState:UIControlStateHighlighted];
  256. [_speakerButton setImage:[UIImage imageNamed:@"speaker_hover"] forState:UIControlStateSelected];
  257. _speakerButton.backgroundColor = [UIColor clearColor];
  258. [_speakerButton addTarget:self action:@selector(speakerButtonDidTap:) forControlEvents:UIControlEventTouchDown];
  259. _speakerButton.hidden = YES;
  260. [self.view addSubview:_speakerButton];
  261. }
  262. return _speakerButton;
  263. }
  264. - (UIButton *)videoButton {
  265. if (!_videoButton) {
  266. _videoButton = [[UIButton alloc] initWithFrame:CGRectMake(self.view.frame.size.width*3/4-ButtonSize/4, self.view.frame.size.height-45-ButtonSize-ButtonSize/2-2, ButtonSize/2, ButtonSize/2)];
  267. [_videoButton setImage:[UIImage imageNamed:@"enable_video"] forState:UIControlStateNormal];
  268. _videoButton.backgroundColor = [UIColor clearColor];
  269. [_videoButton addTarget:self action:@selector(videoButtonDidTap:) forControlEvents:UIControlEventTouchDown];
  270. _videoButton.hidden = YES;
  271. [self updateVideoButton];
  272. [self.view addSubview:_videoButton];
  273. }
  274. return _videoButton;
  275. }
  276. - (UIButton *)scalingButton {
  277. if (!_scalingButton) {
  278. _scalingButton = [[UIButton alloc] initWithFrame:CGRectMake(self.view.frame.size.width/2-ButtonSize/2, self.view.frame.size.height-10-ButtonSize, ButtonSize, ButtonSize)];
  279. [_scalingButton setTitle:WFCString(@"Scale") forState:UIControlStateNormal];
  280. _scalingButton.backgroundColor = [UIColor greenColor];
  281. [_scalingButton addTarget:self action:@selector(scalingButtonDidTap:) forControlEvents:UIControlEventTouchDown];
  282. _scalingButton.hidden = YES;
  283. [self.view addSubview:_scalingButton];
  284. }
  285. return _scalingButton;
  286. }
  287. - (UIImageView *)speakingView {
  288. if (!_speakingView) {
  289. _speakingView = [[UIImageView alloc] initWithFrame:CGRectMake(0, self.bigVideoView.bounds.size.height - 20, 20, 20)];
  290. _speakingView.layer.masksToBounds = YES;
  291. _speakingView.layer.cornerRadius = 2.f;
  292. _speakingView.image = [UIImage imageNamed:@"speaking"];
  293. _speakingView.hidden = YES;
  294. [self.bigVideoView addSubview:_speakingView];
  295. }
  296. return _speakingView;
  297. }
  298. - (void)startConnectedTimer {
  299. [self stopConnectedTimer];
  300. self.connectedTimer = [NSTimer scheduledTimerWithTimeInterval:1
  301. target:self
  302. selector:@selector(updateConnectedTimeLabel)
  303. userInfo:nil
  304. repeats:YES];
  305. [self.connectedTimer fire];
  306. }
  307. - (void)stopConnectedTimer {
  308. if (self.connectedTimer) {
  309. [self.connectedTimer invalidate];
  310. self.connectedTimer = nil;
  311. }
  312. }
  313. - (void)setFocusUser:(NSString *)userId {
  314. if (userId) {
  315. [self.participants removeObject:userId];
  316. [self.participants addObject:userId];
  317. [self reloadVideoUI];
  318. }
  319. }
  320. - (void)updateConnectedTimeLabel {
  321. long sec = [[NSDate date] timeIntervalSince1970] - self.currentSession.connectedTime / 1000;
  322. if (sec < 60 * 60) {
  323. self.connectTimeLabel.text = [NSString stringWithFormat:@"%02ld:%02ld", sec / 60, sec % 60];
  324. } else {
  325. self.connectTimeLabel.text = [NSString stringWithFormat:@"%02ld:%02ld:%02ld", sec / 60 / 60, (sec / 60) % 60, sec % 60];
  326. }
  327. }
  328. - (void)hanupButtonDidTap:(UIButton *)button {
  329. if(self.currentSession.state != kWFAVEngineStateIdle) {
  330. [self.currentSession endCall];
  331. }
  332. }
  333. - (void)answerButtonDidTap:(UIButton *)button {
  334. if (self.currentSession.state == kWFAVEngineStateIncomming) {
  335. [self.currentSession answerCall:NO];
  336. }
  337. }
  338. - (void)minimizeButtonDidTap:(UIButton *)button {
  339. __block NSString *focusUser = [self.participants lastObject];
  340. [WFCUFloatingWindow startCallFloatingWindow:self.currentSession focusUser:focusUser withTouchedBlock:^(WFAVCallSession *callSession) {
  341. WFCUMultiVideoViewController *vc = [[WFCUMultiVideoViewController alloc] initWithSession:callSession];
  342. [vc setFocusUser:focusUser];
  343. [[WFAVEngineKit sharedEngineKit] presentViewController:vc];
  344. }];
  345. [[WFAVEngineKit sharedEngineKit] dismissViewController:self];
  346. }
  347. - (void)addParticipantButtonDidTap:(UIButton *)button {
  348. WFCUSeletedUserViewController *pvc = [[WFCUSeletedUserViewController alloc] init];
  349. NSMutableArray *disabledUser = [[NSMutableArray alloc] init];
  350. [disabledUser addObjectsFromArray:self.participants];
  351. pvc.disableUserIds = disabledUser;
  352. NSMutableArray *candidateUser = [[NSMutableArray alloc] init];
  353. NSArray<WFCCGroupMember *> *members = [[WFCCIMService sharedWFCIMService] getGroupMembers:self.currentSession.conversation.target forceUpdate:NO];
  354. for (WFCCGroupMember *member in members) {
  355. [candidateUser addObject:member.memberId];
  356. }
  357. pvc.candidateUsers = candidateUser;
  358. __weak typeof(self)ws = self;
  359. pvc.selectResult = ^(NSArray<NSString *> *contacts) {
  360. if (contacts.count) {
  361. [ws.currentSession inviteNewParticipants:contacts];
  362. }
  363. };
  364. UINavigationController *navi = [[UINavigationController alloc] initWithRootViewController:pvc];
  365. navi.modalPresentationStyle = UIModalPresentationFullScreen;
  366. dispatch_async(dispatch_get_main_queue(), ^{
  367. [ws presentViewController:navi animated:YES completion:nil];
  368. });
  369. }
  370. - (void)switchCameraButtonDidTap:(UIButton *)button {
  371. if (self.currentSession.state != kWFAVEngineStateIdle) {
  372. [self.currentSession switchCamera];
  373. }
  374. }
  375. - (void)audioButtonDidTap:(UIButton *)button {
  376. if (self.currentSession.state != kWFAVEngineStateIdle) {
  377. [self.currentSession muteAudio:!self.currentSession.audioMuted];
  378. [self updateAudioButton];
  379. }
  380. }
  381. - (void)updateAudioButton {
  382. if (self.currentSession.audioMuted) {
  383. [self.audioButton setImage:[UIImage imageNamed:@"mute_hover"] forState:UIControlStateNormal];
  384. } else {
  385. [self.audioButton setImage:[UIImage imageNamed:@"mute"] forState:UIControlStateNormal];
  386. }
  387. }
  388. - (void)speakerButtonDidTap:(UIButton *)button {
  389. if (self.currentSession.state != kWFAVEngineStateIdle) {
  390. [self.currentSession enableSpeaker:!self.currentSession.isSpeaker];
  391. [self updateSpeakerButton];
  392. }
  393. }
  394. - (void)updateSpeakerButton {
  395. if (!self.currentSession.isSpeaker) {
  396. [self.speakerButton setImage:[UIImage imageNamed:@"speaker"] forState:UIControlStateNormal];
  397. } else {
  398. [self.speakerButton setImage:[UIImage imageNamed:@"speaker_hover"] forState:UIControlStateNormal];
  399. }
  400. }
  401. - (void)updateVideoButton {
  402. if (self.currentSession.videoMuted) {
  403. [self.videoButton setImage:[UIImage imageNamed:@"disable_video"] forState:UIControlStateNormal];
  404. } else {
  405. [self.videoButton setImage:[UIImage imageNamed:@"enable_video"] forState:UIControlStateNormal];
  406. }
  407. }
  408. - (void)viewWillAppear:(BOOL)animated {
  409. [super viewWillAppear:animated];
  410. if (_currentSession.state == kWFAVEngineStateConnected) {
  411. [self updateConnectedTimeLabel];
  412. [self startConnectedTimer];
  413. }
  414. }
  415. - (void)viewWillDisappear:(BOOL)animated {
  416. [super viewWillDisappear:animated];
  417. [self stopConnectedTimer];
  418. }
  419. - (void)setPanStartPoint:(CGPoint)panStartPoint {
  420. _panStartPoint = panStartPoint;
  421. _panStartVideoFrame = self.smallCollectionView.frame;
  422. }
  423. - (void)moveToPanPoint:(CGPoint)panPoint {
  424. CGRect frame = self.panStartVideoFrame;
  425. CGSize moveSize = CGSizeMake(panPoint.x - self.panStartPoint.x, panPoint.y - self.panStartPoint.y);
  426. frame.origin.x += moveSize.width;
  427. frame.origin.y += moveSize.height;
  428. self.smallCollectionView.frame = frame;
  429. }
  430. - (void)onSmallVideoPan:(UIPanGestureRecognizer *)recognize {
  431. switch (recognize.state) {
  432. case UIGestureRecognizerStateBegan:
  433. self.panStartPoint = [recognize translationInView:self.view];
  434. break;
  435. case UIGestureRecognizerStateChanged: {
  436. CGPoint currentPoint = [recognize translationInView:self.view];
  437. [self moveToPanPoint:currentPoint];
  438. break;
  439. }
  440. case UIGestureRecognizerStateEnded: {
  441. CGPoint endPoint = [recognize translationInView:self.view];
  442. [self moveToPanPoint:endPoint];
  443. break;
  444. }
  445. case UIGestureRecognizerStateCancelled:
  446. case UIGestureRecognizerStateFailed:
  447. default:
  448. break;
  449. }
  450. }
  451. - (void)videoButtonDidTap:(UIButton *)button {
  452. if (self.currentSession.state != kWFAVEngineStateIdle) {
  453. [self.currentSession muteVideo:!self.currentSession.isVideoMuted];
  454. [self updateVideoButton];
  455. }
  456. }
  457. - (void)scalingButtonDidTap:(UIButton *)button {
  458. // if (self.currentSession.state != kWFAVEngineStateIdle) {
  459. // if (self.scalingType < kWFAVVideoScalingTypeAspectBalanced) {
  460. // self.scalingType++;
  461. // } else {
  462. // self.scalingType = kWFAVVideoScalingTypeAspectFit;
  463. // }
  464. //
  465. //// [self.currentSession setupLocalVideoView:self.smallVideoView scalingType:self.scalingType];
  466. //// [self.currentSession setupRemoteVideoView:self.bigVideoView scalingType:self.scalingType forUser:self.currentSession.participants[0]];
  467. // }
  468. }
  469. - (CGRect)getButtomCenterButtonFrame {
  470. return CGRectMake(self.view.frame.size.width/2-ButtonSize/2, self.view.frame.size.height-BottomPadding-ButtonSize, ButtonSize, ButtonSize);
  471. }
  472. - (CGRect)getButtomLeftButtonFrame {
  473. return CGRectMake(self.view.frame.size.width/4-ButtonSize/2, self.view.frame.size.height-BottomPadding-ButtonSize, ButtonSize, ButtonSize);
  474. }
  475. - (CGRect)getButtomRightButtonFrame {
  476. return CGRectMake(self.view.frame.size.width*3/4-ButtonSize/2, self.view.frame.size.height-BottomPadding-ButtonSize, ButtonSize, ButtonSize);
  477. }
  478. - (CGRect)getToAudioButtonFrame {
  479. return CGRectMake(self.view.frame.size.width*3/4-ButtonSize/2, self.view.frame.size.height-BottomPadding-ButtonSize-ButtonSize-2, ButtonSize, ButtonSize);
  480. }
  481. - (void)updateTopViewFrame {
  482. // if (self.currentSession.isAudioOnly) {
  483. CGFloat containerWidth = self.view.bounds.size.width;
  484. self.portraitView.frame = CGRectMake((containerWidth-64)/2, kStatusBarAndNavigationBarHeight, 64, 64);;
  485. self.userNameLabel.frame = CGRectMake((containerWidth - 240)/2, kStatusBarAndNavigationBarHeight + 64 + 8, 240, 26);
  486. self.userNameLabel.textAlignment = NSTextAlignmentCenter;
  487. self.connectTimeLabel.frame = CGRectMake((containerWidth - 240)/2, self.smallCollectionView.frame.origin.y + self.smallCollectionView.frame.size.height + 8, 240, 16);
  488. self.connectTimeLabel.textAlignment = NSTextAlignmentCenter;
  489. self.stateLabel.frame = CGRectMake((containerWidth - 240)/2, self.smallCollectionView.frame.origin.y + self.smallCollectionView.frame.size.height + 30, 240, 16);
  490. self.stateLabel.textAlignment = NSTextAlignmentCenter;
  491. // } else {
  492. // self.portraitView.frame = CGRectMake(16, kStatusBarAndNavigationBarHeight, 64, 64);
  493. // self.userNameLabel.frame = CGRectMake(96, kStatusBarAndNavigationBarHeight + 8, 240, 26);
  494. // if(![NSThread isMainThread]) {
  495. // NSLog(@"error not main thread");
  496. // }
  497. // self.userNameLabel.textAlignment = NSTextAlignmentLeft;
  498. // if(self.currentSession.state == kWFAVEngineStateConnected) {
  499. // self.stateLabel.frame = CGRectMake(54, 30, 240, 20);
  500. // } else {
  501. // self.stateLabel.frame = CGRectMake(96, kStatusBarAndNavigationBarHeight + 26 + 14, 240, 16);
  502. // }
  503. // self.stateLabel.textAlignment = NSTextAlignmentLeft;
  504. // }
  505. }
  506. - (void)onClickedBigVideoView:(id)sender {
  507. if (self.currentSession.state != kWFAVEngineStateConnected) {
  508. return;
  509. }
  510. if (self.currentSession.audioOnly) {
  511. return;
  512. }
  513. if (self.smallCollectionView.hidden) {
  514. if (self.hangupButton.hidden) {
  515. self.hangupButton.hidden = NO;
  516. self.audioButton.hidden = NO;
  517. if (self.currentSession.audioOnly) {
  518. self.videoButton.hidden = YES;
  519. } else {
  520. self.videoButton.hidden = NO;
  521. }
  522. self.switchCameraButton.hidden = NO;
  523. self.smallCollectionView.hidden = NO;
  524. self.minimizeButton.hidden = NO;
  525. self.addParticipantButton.hidden = NO;
  526. } else {
  527. self.hangupButton.hidden = YES;
  528. self.audioButton.hidden = YES;
  529. self.videoButton.hidden = YES;
  530. self.switchCameraButton.hidden = YES;
  531. self.minimizeButton.hidden = YES;
  532. self.addParticipantButton.hidden = YES;
  533. }
  534. } else {
  535. self.smallCollectionView.hidden = YES;
  536. }
  537. }
  538. #pragma mark - WFAVEngineDelegate
  539. - (void)didChangeState:(WFAVEngineState)state {
  540. if (!self.viewLoaded) {
  541. return;
  542. }
  543. switch (state) {
  544. case kWFAVEngineStateIdle:
  545. self.answerButton.hidden = YES;
  546. self.hangupButton.hidden = YES;
  547. self.switchCameraButton.hidden = YES;
  548. self.audioButton.hidden = YES;
  549. self.videoButton.hidden = YES;
  550. self.scalingButton.hidden = YES;
  551. [self stopConnectedTimer];
  552. self.userNameLabel.hidden = YES;
  553. self.portraitView.hidden = YES;
  554. self.stateLabel.text = WFCString(@"CallEnded");
  555. self.smallCollectionView.hidden = YES;
  556. self.portraitCollectionView.hidden = YES;
  557. self.bigVideoView.hidden = YES;
  558. self.minimizeButton.hidden = YES;
  559. self.speakerButton.hidden = YES;
  560. self.addParticipantButton.hidden = YES;
  561. [self updateTopViewFrame];
  562. break;
  563. case kWFAVEngineStateOutgoing:
  564. self.answerButton.hidden = YES;
  565. self.connectTimeLabel.hidden = YES;
  566. self.hangupButton.hidden = NO;
  567. self.hangupButton.frame = [self getButtomCenterButtonFrame];
  568. self.switchCameraButton.hidden = YES;
  569. if (self.currentSession.isAudioOnly) {
  570. self.speakerButton.hidden = YES;
  571. [self updateSpeakerButton];
  572. self.speakerButton.frame = [self getButtomRightButtonFrame];
  573. self.audioButton.hidden = YES;
  574. self.audioButton.frame = [self getButtomLeftButtonFrame];
  575. } else {
  576. self.speakerButton.hidden = YES;
  577. self.audioButton.hidden = YES;
  578. }
  579. self.videoButton.hidden = YES;
  580. self.scalingButton.hidden = YES;
  581. [self.currentSession setupLocalVideoView:self.bigVideoView scalingType:self.bigScalingType];
  582. self.stateLabel.text = WFCString(@"WaitingAccept");
  583. self.smallCollectionView.hidden = YES;
  584. self.portraitCollectionView.hidden = NO;
  585. [self.portraitCollectionView reloadData];
  586. self.userNameLabel.hidden = YES;
  587. self.portraitView.hidden = YES;
  588. [self updateTopViewFrame];
  589. break;
  590. case kWFAVEngineStateConnecting:
  591. self.answerButton.hidden = YES;
  592. self.hangupButton.hidden = NO;
  593. self.speakerButton.hidden = YES;
  594. self.hangupButton.frame = [self getButtomCenterButtonFrame];
  595. self.switchCameraButton.hidden = YES;
  596. self.audioButton.hidden = YES;
  597. self.videoButton.hidden = YES;
  598. self.scalingButton.hidden = YES;
  599. [self.currentSession setupLocalVideoView:self.bigVideoView scalingType:self.bigScalingType];
  600. if (self.currentSession.audioOnly) {
  601. self.smallCollectionView.hidden = YES;
  602. self.portraitCollectionView.hidden = NO;
  603. [self.portraitCollectionView reloadData];
  604. self.portraitCollectionView.center = self.view.center;
  605. } else {
  606. self.smallCollectionView.hidden = NO;
  607. [self.smallCollectionView reloadData];
  608. self.portraitCollectionView.hidden = YES;
  609. }
  610. self.stateLabel.text = WFCString(@"CallConnecting");
  611. self.portraitView.hidden = YES;
  612. self.userNameLabel.hidden = YES;
  613. break;
  614. case kWFAVEngineStateConnected:
  615. self.answerButton.hidden = YES;
  616. self.hangupButton.hidden = NO;
  617. self.connectTimeLabel.hidden = NO;
  618. self.stateLabel.hidden = YES;
  619. self.hangupButton.frame = [self getButtomCenterButtonFrame];
  620. if (self.currentSession.isAudioOnly) {
  621. self.speakerButton.hidden = NO;
  622. self.speakerButton.frame = [self getButtomRightButtonFrame];
  623. [self updateSpeakerButton];
  624. self.audioButton.hidden = NO;
  625. self.audioButton.frame = [self getButtomLeftButtonFrame];
  626. self.switchCameraButton.hidden = YES;
  627. self.videoButton.hidden = YES;
  628. } else {
  629. self.speakerButton.hidden = YES;
  630. [self.currentSession enableSpeaker:YES];
  631. self.audioButton.hidden = NO;
  632. self.audioButton.frame = [self getButtomLeftButtonFrame];
  633. self.switchCameraButton.hidden = NO;
  634. self.switchCameraButton.frame = [self getButtomRightButtonFrame];
  635. self.videoButton.hidden = NO;
  636. }
  637. self.scalingButton.hidden = YES;
  638. self.minimizeButton.hidden = NO;
  639. self.addParticipantButton.hidden = NO;
  640. if (self.currentSession.isAudioOnly) {
  641. [self.currentSession setupLocalVideoView:nil scalingType:self.bigScalingType];
  642. self.smallCollectionView.hidden = YES;
  643. self.bigVideoView.hidden = YES;
  644. self.portraitCollectionView.hidden = NO;
  645. [self.portraitCollectionView reloadData];
  646. } else {
  647. NSString *lastUser = [self.participants lastObject];
  648. if ([lastUser isEqualToString:[WFCCNetworkService sharedInstance].userId]) {
  649. [self.currentSession setupLocalVideoView:self.bigVideoView scalingType:self.bigScalingType];
  650. } else {
  651. [self.currentSession setupRemoteVideoView:self.bigVideoView scalingType:self.bigScalingType forUser:lastUser];
  652. }
  653. self.smallCollectionView.hidden = NO;
  654. [self.smallCollectionView reloadData];
  655. self.bigVideoView.hidden = NO;
  656. self.portraitCollectionView.hidden = YES;
  657. }
  658. // if (!_currentSession.isAudioOnly) {
  659. self.userNameLabel.hidden = YES;
  660. self.portraitView.hidden = YES;
  661. // } else {
  662. // self.userNameLabel.hidden = NO;
  663. // self.portraitView.hidden = NO;
  664. // }
  665. [self updateConnectedTimeLabel];
  666. [self startConnectedTimer];
  667. [self updateTopViewFrame];
  668. break;
  669. case kWFAVEngineStateIncomming:
  670. self.connectTimeLabel.hidden = YES;
  671. self.answerButton.hidden = NO;
  672. self.answerButton.frame = [self getButtomRightButtonFrame];
  673. self.hangupButton.hidden = NO;
  674. self.hangupButton.frame = [self getButtomLeftButtonFrame];
  675. self.switchCameraButton.hidden = YES;
  676. self.audioButton.hidden = YES;
  677. self.videoButton.hidden = YES;
  678. self.scalingButton.hidden = YES;
  679. [self.currentSession setupLocalVideoView:self.bigVideoView scalingType:self.bigScalingType];
  680. self.stateLabel.text = WFCString(@"InvitingYou");
  681. self.smallCollectionView.hidden = YES;
  682. self.portraitCollectionView.hidden = NO;
  683. [self.portraitCollectionView reloadData];
  684. break;
  685. default:
  686. break;
  687. }
  688. }
  689. - (void)didCreateLocalVideoTrack:(RTCVideoTrack *)localVideoTrack {
  690. }
  691. - (void)didReceiveRemoteVideoTrack:(RTCVideoTrack *)remoteVideoTrack fromUser:(NSString *)userId {
  692. }
  693. - (void)didVideoMuted:(BOOL)videoMuted fromUser:(NSString *)userId {
  694. if ([self.participants.lastObject isEqualToString:userId]) {
  695. for (int i = 0; i < self.participants.count-1; i++) {
  696. NSString *pid = [self.participants objectAtIndex:i];
  697. if ([pid isEqualToString:[WFCCNetworkService sharedInstance].userId]) {
  698. if (!self.currentSession.myProfile.videoMuted) {
  699. [self switchVideoView:i];
  700. return;
  701. }
  702. continue;
  703. }
  704. for (WFAVParticipantProfile *p in self.currentSession.participants) {
  705. if ([p.userId isEqualToString:pid]) {
  706. if (!p.videoMuted && p.state == kWFAVEngineStateConnected) {
  707. [self switchVideoView:i];
  708. return;
  709. }
  710. break;
  711. }
  712. }
  713. }
  714. [self reloadVideoUI];
  715. } else {
  716. [self reloadVideoUI];
  717. }
  718. }
  719. - (void)didReportAudioVolume:(NSInteger)volume ofUser:(NSString *)userId {
  720. NSLog(@"user %@ report volume %ld", userId, volume);
  721. [[NSNotificationCenter defaultCenter] postNotificationName:@"wfavVolumeUpdated" object:userId userInfo:@{@"volume":@(volume)}];
  722. if (!self.currentSession.audioOnly && [userId isEqualToString:self.participants.lastObject]) {
  723. if (volume > 1000) {
  724. [self.bigVideoView bringSubviewToFront:self.speakingView];
  725. self.speakingView.hidden = NO;
  726. } else {
  727. self.speakingView.hidden = YES;
  728. }
  729. }
  730. }
  731. - (void)didCallEndWithReason:(WFAVCallEndReason)reason {
  732. dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
  733. [[WFAVEngineKit sharedEngineKit] dismissViewController:self];
  734. });
  735. }
  736. - (void)didParticipantJoined:(NSString *)userId {
  737. if ([self.participants containsObject:userId] || [userId isEqualToString:[WFCCNetworkService sharedInstance].userId]) {
  738. return;
  739. }
  740. [self.participants insertObject:userId atIndex:0];
  741. [self reloadVideoUI];
  742. }
  743. - (void)didParticipantConnected:(NSString *)userId {
  744. [self reloadVideoUI];
  745. }
  746. - (void)didParticipantLeft:(NSString *)userId withReason:(WFAVCallEndReason)reason {
  747. [self.participants removeObject:userId];
  748. [self reloadVideoUI];
  749. WFCCUserInfo *userInfo = [[WFCCIMService sharedWFCIMService] getUserInfo:userId inGroup:self.currentSession.conversation.type == Group_Type ? self.currentSession.conversation.target : nil refresh:NO];
  750. NSString *reasonStr;
  751. if (reason == kWFAVCallEndReasonTimeout) {
  752. reasonStr = @"未接听";
  753. } else if(reason == kWFAVCallEndReasonBusy) {
  754. reasonStr = @"网络忙";
  755. } else if(reason == kWFAVCallEndReasonRemoteHangup) {
  756. reasonStr = @"离开会议";
  757. } else {
  758. reasonStr = @"离开会议"; //"网络错误";
  759. }
  760. [self.view makeToast:[NSString stringWithFormat:@"%@ %@", userInfo.displayName, reasonStr] duration:1 position:CSToastPositionCenter];
  761. }
  762. - (void)didChangeMode:(BOOL)isAudioOnly {
  763. [self didChangeState:self.currentSession.state];
  764. }
  765. - (void)didError:(NSError *)error {
  766. }
  767. - (void)didGetStats:(NSArray *)stats {
  768. }
  769. - (void)checkAVPermission {
  770. [self checkCapturePermission:nil];
  771. [self checkRecordPermission:nil];
  772. }
  773. - (void)checkCapturePermission:(void (^)(BOOL granted))complete {
  774. AVAuthorizationStatus authStatus = [AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo];
  775. if (authStatus == AVAuthorizationStatusDenied || authStatus == AVAuthorizationStatusRestricted) {
  776. if (complete) {
  777. complete(NO);
  778. }
  779. } else if (authStatus == AVAuthorizationStatusNotDetermined) {
  780. [AVCaptureDevice
  781. requestAccessForMediaType:AVMediaTypeVideo
  782. completionHandler:^(BOOL granted) {
  783. if (complete) {
  784. complete(granted);
  785. }
  786. }];
  787. } else {
  788. if (complete) {
  789. complete(YES);
  790. }
  791. }
  792. }
  793. - (void)checkRecordPermission:(void (^)(BOOL granted))complete {
  794. if ([[AVAudioSession sharedInstance] respondsToSelector:@selector(requestRecordPermission:)]) {
  795. [[AVAudioSession sharedInstance] requestRecordPermission:^(BOOL granted) {
  796. if (complete) {
  797. complete(granted);
  798. }
  799. }];
  800. }
  801. }
  802. - (void)reloadVideoUI {
  803. if (!self.currentSession.audioOnly) {
  804. if (self.currentSession.state == kWFAVEngineStateConnecting || self.currentSession.state == kWFAVEngineStateConnected) {
  805. _speakingView.hidden = YES;
  806. NSString *userId = [self.participants lastObject];
  807. if ([userId isEqualToString:[WFCCNetworkService sharedInstance].userId]) {
  808. if (self.currentSession.myProfile.videoMuted) {
  809. [self.currentSession setupLocalVideoView:nil scalingType:self.bigScalingType];
  810. self.stateLabel.text = WFCString(@"VideoClosed");
  811. self.stateLabel.hidden = NO;
  812. } else {
  813. [self.currentSession setupLocalVideoView:self.bigVideoView scalingType:self.bigScalingType];
  814. self.stateLabel.text = nil;
  815. self.stateLabel.hidden = YES;
  816. }
  817. } else {
  818. for (WFAVParticipantProfile *profile in self.currentSession.participants) {
  819. if ([profile.userId isEqualToString:userId]) {
  820. if (profile.videoMuted) {
  821. [self.currentSession setupRemoteVideoView:nil scalingType:self.bigScalingType forUser:userId];
  822. self.stateLabel.text = WFCString(@"VideoClosed");
  823. self.stateLabel.hidden = NO;
  824. } else {
  825. [self.currentSession setupRemoteVideoView:self.bigVideoView scalingType:self.bigScalingType forUser:userId];
  826. self.stateLabel.text = nil;
  827. self.stateLabel.hidden = YES;
  828. }
  829. break;
  830. }
  831. }
  832. }
  833. [self.smallCollectionView reloadData];
  834. } else {
  835. [self.portraitCollectionView reloadData];
  836. }
  837. } else {
  838. [self.portraitCollectionView reloadData];
  839. }
  840. }
  841. - (BOOL)switchVideoView:(NSUInteger)index {
  842. NSString *userId = self.participants[index];
  843. BOOL canSwitch = NO;
  844. for (WFAVParticipantProfile *profile in self.currentSession.participants) {
  845. if ([profile.userId isEqualToString:userId]) {
  846. if (profile.state == kWFAVEngineStateConnected) {
  847. canSwitch = YES;
  848. }
  849. break;
  850. }
  851. }
  852. if ([userId isEqualToString:[WFCCNetworkService sharedInstance].userId]) {
  853. if (self.currentSession.state == kWFAVEngineStateConnected) {
  854. canSwitch = YES;
  855. }
  856. }
  857. if (canSwitch) {
  858. NSString *lastId = [self.participants lastObject];
  859. [self.participants removeLastObject];
  860. [self.participants insertObject:lastId atIndex:index];
  861. [self.participants removeObject:userId];
  862. [self.participants addObject:userId];
  863. }
  864. [self reloadVideoUI];
  865. return canSwitch;
  866. }
  867. #pragma mark - UICollectionViewDataSource
  868. - (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
  869. if (collectionView == self.portraitCollectionView) {
  870. if (self.currentSession.audioOnly && (self.currentSession.state == kWFAVEngineStateConnecting || self.currentSession.state == kWFAVEngineStateConnected)) {
  871. return self.participants.count;
  872. }
  873. }
  874. return self.participants.count - 1;
  875. }
  876. // The cell that is returned must be retrieved from a call to -dequeueReusableCellWithReuseIdentifier:forIndexPath:
  877. - (__kindof UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
  878. NSString *userId = self.participants[indexPath.row];
  879. if (collectionView == self.smallCollectionView) {
  880. WFCUParticipantCollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"cell" forIndexPath:indexPath];
  881. WFCCUserInfo *userInfo = [[WFCCIMService sharedWFCIMService] getUserInfo:userId inGroup:self.currentSession.conversation.type == Group_Type ? self.currentSession.conversation.target : nil refresh:NO];
  882. if ([userId isEqualToString:[WFCCNetworkService sharedInstance].userId]) {
  883. WFAVParticipantProfile *profile = self.currentSession.myProfile;
  884. [cell setUserInfo:userInfo callProfile:profile];
  885. if (profile.videoMuted) {
  886. [self.currentSession setupLocalVideoView:nil scalingType:self.smallScalingType];
  887. } else {
  888. [self.currentSession setupLocalVideoView:cell scalingType:self.smallScalingType];
  889. }
  890. } else {
  891. for (WFAVParticipantProfile *profile in self.currentSession.participants) {
  892. if ([profile.userId isEqualToString:userId]) {
  893. [cell setUserInfo:userInfo callProfile:profile];
  894. if (profile.videoMuted) {
  895. [self.currentSession setupRemoteVideoView:nil scalingType:self.smallScalingType forUser:userId];
  896. } else {
  897. [self.currentSession setupRemoteVideoView:cell scalingType:self.smallScalingType forUser:userId];
  898. }
  899. break;
  900. }
  901. }
  902. }
  903. return cell;
  904. } else {
  905. WFCUPortraitCollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"cell2" forIndexPath:indexPath];
  906. cell.itemSize = PortraitItemSize;
  907. cell.labelSize = PortraitLabelSize;
  908. WFCCUserInfo *userInfo = [[WFCCIMService sharedWFCIMService] getUserInfo:userId inGroup:self.currentSession.conversation.type == Group_Type ? self.currentSession.conversation.target : nil refresh:NO];
  909. cell.userInfo = userInfo;
  910. if ([userId isEqualToString:[WFCCNetworkService sharedInstance].userId]) {
  911. cell.profile = self.currentSession.myProfile;
  912. } else {
  913. for (WFAVParticipantProfile *profile in self.currentSession.participants) {
  914. if ([profile.userId isEqualToString:userId]) {
  915. cell.profile = profile;
  916. break;
  917. }
  918. }
  919. }
  920. return cell;
  921. }
  922. }
  923. #pragma mark - UICollectionViewDelegate
  924. - (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath {
  925. if (collectionView == self.smallCollectionView) {
  926. [self switchVideoView:indexPath.row];
  927. }
  928. }
  929. #endif
  930. @end