LiveRoomViewController.m 76 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203
  1. //
  2. // LiveRoomViewController.m
  3. // KulexiuForTeacher
  4. //
  5. // Created by 王智 on 2022/6/21.
  6. //
  7. #import "LiveRoomViewController.h"
  8. #import "LivePreviewBodyView.h"
  9. #import <RongRTCLib/RongRTCLib.h>
  10. #import <RongIMKit/RongIMKit.h>
  11. #import <RongFaceBeautifier/RongFaceBeautifier.h>
  12. #import "KSBeautySettingView.h"
  13. #import "KSEnterLiveroomManager.h"
  14. #import "LiveroomTimeManager.h"
  15. #import "UserInfoManager.h"
  16. #import <RongIMKit/RongIMKit.h>
  17. #import "KSChatInputBarControl.h"
  18. #import "LiveRoomHeadView.h"
  19. #import "LiveRoomBottomView.h"
  20. #import "SeatContentView.h"
  21. #import "SeatTipsView.h"
  22. #import "KSLiveStreamVideo.h"
  23. #import "KSRCMessageModel.h"
  24. #import "KSChatroomMessageCenter.h"
  25. #import "KSChatroomTextCell.h"
  26. #import "LiveRoomAlertView.h"
  27. #import "LiveMoreDisplayView.h"
  28. #import "LiveAnimationView.h"
  29. #import "KSShareChooseViewController.h"
  30. #import "KSChatLiveMessage.h"
  31. #import "LiveSeatActionView.h"
  32. //#import <ImSDK_Plus/V2TIMManager.h>
  33. typedef NS_ENUM(NSInteger, LIVEPAGE) {
  34. LIVEPAGE_PREVIEW,
  35. LIVEPAGE_LIVE,
  36. };
  37. @interface LiveRoomViewController ()<RCRTCEngineEventDelegate,RCRTCRoomEventDelegate,RCRTCStatusReportDelegate,UIGestureRecognizerDelegate,KSChatInputBarControlDelegate,UITableViewDataSource,UITableViewDelegate,LiveroomTimeManagerDelegate>
  38. @property (nonatomic, strong) LiveroomTimeManager *timeManager;
  39. @property (nonatomic, assign) LIVEPAGE pageType;
  40. @property (nonatomic, assign) BOOL isPauseLive; // 是否暂停直播
  41. @property (nonatomic, assign) BOOL isOtherLogin; // 是否被顶掉
  42. @property (nonatomic, strong) LivePreviewBodyView *previewPageView;
  43. @property (nonatomic, strong) RCRTCVideoView *preVideoView;
  44. @property (nonatomic, strong) KSBeautySettingView *settingView;
  45. @property (nonatomic, assign) BOOL isBeautyOn;
  46. @property (nonatomic, assign) int filterLevel;
  47. #pragma mark ------- 直播房间信息
  48. /*!
  49. 身份状态 老师/观众
  50. */
  51. @property (nonatomic, assign) RCRTCLiveRoleType liveRoleType;
  52. /// 老师id
  53. @property (nonatomic, strong) NSString *createrId;
  54. /// 老师名称
  55. @property (nonatomic, strong) NSString *createrName;
  56. /// 老师头像
  57. @property (nonatomic, strong) NSString *createrAvatal;
  58. // 是否禁止连麦
  59. @property (nonatomic, assign) BOOL enableSeat;
  60. // 是否禁止聊天
  61. @property (nonatomic, assign) BOOL enableChat;
  62. // 是否允许点赞
  63. @property (nonatomic, assign) BOOL enableLike;
  64. @property (nonatomic, assign) NSInteger likeCount;
  65. /// 房间人数
  66. @property (nonatomic, assign) NSInteger totalCount;
  67. #pragma mark ---- Live page
  68. @property (nonatomic, strong) UIView *livePageView;
  69. @property (nonatomic, strong) RCRTCRoom *room;
  70. @property (nonatomic, assign) BOOL isImConnected;
  71. @property (nonatomic, assign) BOOL hasJoinRoomSuccess;
  72. @property (nonatomic, strong) KSLiveStreamVideo *localVideo;
  73. @property (nonatomic, strong) UIView *liveVideoView;
  74. @property (nonatomic, strong) LiveRoomHeadView *headView;
  75. @property (nonatomic, copy) LiveRoomBottomView *bottomView;
  76. /// 连麦的视图
  77. @property (nonatomic, strong) SeatContentView *seatContainer;
  78. // 聊天UI
  79. /*!
  80. 消息列表CollectionView和输入框都在这个view里
  81. */
  82. @property(nonatomic, strong) UIView *messageContentView;
  83. /*!
  84. 会话页面的TableView
  85. */
  86. @property (nonatomic, strong) UITableView *conversationMessageTableView;
  87. /*!
  88. 聊天内容的消息Cell数据模型的数据源
  89. @discussion 数据源中存放的元素为消息Cell的数据模型,即RCDLiveMessageModel对象。
  90. */
  91. @property(nonatomic, strong) NSMutableArray<KSRCMessageModel *> *conversationDataRepository;
  92. /**
  93. 输入工具栏
  94. */
  95. @property(nonatomic,strong) KSChatInputBarControl *inputBar;
  96. /**
  97. * 是否需要滚动到底部
  98. */
  99. @property(nonatomic, assign) BOOL isNeedScrollToButtom;
  100. @property (nonatomic, strong) UIView *seatCtrlView;
  101. @property (nonatomic, strong) LiveSeatActionView *seatActionView;
  102. @property (nonatomic, strong) NSMutableArray *seatApplyArray; // 申请连麦数组
  103. // 远端连麦用户
  104. @property (nonatomic, strong) NSMutableArray *remoteMemberArray;
  105. /// 连麦申请统计数据
  106. @property (nonatomic, strong) SeatTipsView *seatApplyTips;
  107. /// 提示窗
  108. @property (nonatomic, strong) LiveRoomAlertView *alertView;
  109. // 定时器
  110. @property (nonatomic, strong) dispatch_source_t timer;
  111. @property (nonatomic, strong) LiveMoreDisplayView *moreView;
  112. @property (nonatomic) LiveAnimationView *animationView;
  113. /// 直播课结束时间
  114. @property (nonatomic, strong) NSString *liveEndTime;
  115. /// 直播间关闭延迟时间
  116. @property (nonatomic, assign) NSInteger expiredCloseMinute;
  117. @property (nonatomic, copy) LiveRoomBackAction callback;
  118. @property (nonatomic, strong) UITapGestureRecognizer *gesture;
  119. @property (nonatomic, assign) BOOL needPublishStream;
  120. @property (nonatomic, assign) BOOL micEnable;
  121. @end
  122. @implementation LiveRoomViewController
  123. - (void)backRefreshCallback:(LiveRoomBackAction)callback {
  124. if (callback) {
  125. self.callback = callback;
  126. }
  127. }
  128. - (void)viewDidLoad {
  129. [super viewDidLoad];
  130. // Do any additional setup after loading the view.
  131. self.ks_prefersNavigationBarHidden = YES;
  132. self.isOtherLogin = NO;
  133. [self registerOtherLoginNotice];
  134. [self configUI];
  135. [self configEngine];
  136. self.pageType = LIVEPAGE_PREVIEW;
  137. [self countUMEvent];
  138. }
  139. - (void)countUMEvent {
  140. [USER_MANAGER sendUMEvent:@"klx_live"];
  141. }
  142. - (void)registerOtherLoginNotice {
  143. [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(liveroomLogOut) name:@"liveroomLogout" object:nil];
  144. [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(liveroomQuit) name:@"liveroomQuit" object:nil];
  145. }
  146. - (void)viewWillAppear:(BOOL)animated {
  147. [super viewWillAppear:animated];
  148. [UIApplication sharedApplication].idleTimerDisabled = YES;
  149. [IQKeyboardManager sharedManager].enableAutoToolbar = NO;
  150. [IQKeyboardManager sharedManager].enable = NO;
  151. [UIApplication sharedApplication].statusBarStyle = UIStatusBarStyleLightContent;
  152. }
  153. - (void)viewWillDisappear:(BOOL)animated {
  154. [super viewWillDisappear:animated];
  155. [UIApplication sharedApplication].idleTimerDisabled = NO;
  156. [IQKeyboardManager sharedManager].enableAutoToolbar = YES;
  157. [IQKeyboardManager sharedManager].enable = YES;
  158. if (@available(iOS 13.0, *)) {
  159. [UIApplication sharedApplication].statusBarStyle = UIStatusBarStyleDarkContent;
  160. } else {
  161. // Fallback on earlier versions
  162. [UIApplication sharedApplication].statusBarStyle = UIStatusBarStyleDefault;
  163. }
  164. }
  165. - (void)configUI {
  166. self.previewPageView = [LivePreviewBodyView shareInstance];
  167. [self.view addSubview:self.previewPageView];
  168. [self.previewPageView mas_makeConstraints:^(MASConstraintMaker *make) {
  169. make.left.right.bottom.top.mas_equalTo(self.view);
  170. }];
  171. MJWeakSelf;
  172. [self.previewPageView previewOperationCallback:^(PREVIEWLIVEACTION action) {
  173. [weakSelf previewOperationAction:action];
  174. }];
  175. [[RCRTCBeautyEngine sharedInstance] reset];
  176. }
  177. - (void)configEngine {
  178. if (!self.preVideoView) {
  179. self.preVideoView = [[RCRTCVideoView alloc] init];
  180. self.preVideoView.fillMode = RCRTCVideoFillModeAspectFill;
  181. self.preVideoView.frameAnimated = NO;
  182. [self.previewPageView.videoView addSubview:self.preVideoView];
  183. [self.preVideoView mas_makeConstraints:^(MASConstraintMaker *make) {
  184. make.left.top.bottom.right.mas_equalTo(self.previewPageView.videoView);
  185. }];
  186. }
  187. [[RCRTCEngine sharedInstance].defaultVideoStream setVideoView:self.preVideoView];
  188. RCRTCVideoStreamConfig *videoConfig = [RCRTCEngine sharedInstance].defaultVideoStream.videoConfig;
  189. videoConfig.videoSizePreset = RCRTCVideoSizePreset1280x720;
  190. videoConfig.maxBitrate = 2200;
  191. videoConfig.minBitrate = 200;
  192. [[RCRTCEngine sharedInstance].defaultVideoStream setVideoConfig:videoConfig];
  193. [[RCRTCEngine sharedInstance].defaultVideoStream startCapture];
  194. self.filterLevel = 50;
  195. }
  196. - (void)previewOperationAction:(PREVIEWLIVEACTION)action {
  197. switch (action) {
  198. case PREVIEWLIVEACTION_BACK: // 返回
  199. {
  200. if (self.isPauseLive) { // 退出RTC房间
  201. [self quitRoomBackPreView:NO];
  202. }
  203. else {
  204. self.room = nil;
  205. self.preVideoView = nil;
  206. [[RCRTCEngine sharedInstance].defaultVideoStream stopCapture];
  207. if (self.callback) {
  208. self.callback();
  209. }
  210. [self.navigationController dismissViewControllerAnimated:YES completion:nil];
  211. }
  212. }
  213. break;
  214. case PREVIEWLIVEACTION_SWITCH: // 切换
  215. {
  216. [self switchCamera];
  217. }
  218. break;
  219. case PREVIEWLIVEACTION_BEAUTY: // 美颜
  220. {
  221. [self displayBeautyView];
  222. }
  223. break;
  224. case PREVIEWLIVEACTION_SHARE: // 分享
  225. {
  226. [self shareLiveRoomMessage];
  227. }
  228. break;
  229. case PREVIEWLIVEACTION_OPEN: // 进入直播间
  230. {
  231. [self showLiveView];
  232. }
  233. break;
  234. default:
  235. break;
  236. }
  237. }
  238. - (void)shareLiveRoomMessage {
  239. // 选择群组分享
  240. NSMutableDictionary *parm = [NSMutableDictionary dictionary];
  241. [parm setValue:@"TC_CHATSHARE_LIVE" forKey:@"businessID"];
  242. [parm setValue:@"TXLiveShareCell" forKey:@"TMessageCell_Name"];
  243. [parm setValue:@"TXLiveShareMessage" forKey:@"TMessageCell_Name"];
  244. NSString *teacherName = UserDefaultObjectForKey(NicknameKey);
  245. if ([NSString isEmptyString:teacherName]) {
  246. teacherName = [NSString stringWithFormat:@"游客%@",UserDefaultObjectForKey(UIDKey)];
  247. }
  248. [parm setValue:self.roomId forKey:@"roomUID"];
  249. [parm setValue:teacherName forKey:@"teacherName"];
  250. [parm setValue:UserDefaultObjectForKey(AvatarUrlKey) forKey:@"teacherAvatar"];
  251. [parm setValue:self.liveContent forKey:@"liveContent"];
  252. NSData *data = [NSJSONSerialization dataWithJSONObject:parm options:0 error:nil];
  253. KSShareChooseViewController *chooseCtrl = [[KSShareChooseViewController alloc] init];
  254. chooseCtrl.msgData = data;
  255. [self.navigationController pushViewController:chooseCtrl animated:YES];
  256. }
  257. - (void)displayBeautyView {
  258. [self displayBottomView:YES];
  259. if (_settingView == nil) {
  260. RCRTCBeautyOption *option = [[RCRTCBeautyEngine sharedInstance] getCurrentBeautyOption];
  261. RCRTCBeautyFilter filter = [[RCRTCBeautyEngine sharedInstance] getCurrentBeautyFilter];
  262. FILTER_TYPE type = [self getFilterType:filter];
  263. MJWeakSelf;
  264. [self.settingView evaluateMessageWithWhite:option.whitenessLevel smoothLevel:option.smoothLevel ruddyLevel:option.ruddyLevel brightLevel:option.brightLevel filter:type filterLevel:self.filterLevel callback:^(BOOL isOpenBeauty, NSInteger white, NSInteger smoothLevel, NSInteger ruddyLevel, NSInteger brightLevel, FILTER_TYPE type, int filterLevel) {
  265. [weakSelf configSettingBeauty:YES white:white smoothLevel:smoothLevel ruddyLevel:ruddyLevel brightLevel:brightLevel filter:[weakSelf getRongBeautyWithType:type] filterLevel:filterLevel];
  266. }];
  267. }
  268. [self.view addSubview:self.settingView];
  269. [self.settingView mas_makeConstraints:^(MASConstraintMaker *make) {
  270. make.left.right.top.bottom.mas_equalTo(self.view);
  271. }];
  272. }
  273. - (FILTER_TYPE)getFilterType:(RCRTCBeautyFilter)filter {
  274. switch (filter) {
  275. case RCRTCBeautyFilterNone:
  276. return FILTER_TYPE_NONE;
  277. case RCRTCBeautyFilterFresh:
  278. return FILTER_TYPE_QINGXIN;
  279. case RCRTCBeautyFilterEsthetic:
  280. return FILTER_TYPE_WEIMEI;
  281. case RCRTCBeautyFilterRomantic:
  282. return FILTER_TYPE_LANGMAN;
  283. default:
  284. return FILTER_TYPE_NONE;
  285. break;
  286. }
  287. }
  288. - (RCRTCBeautyFilter)getRongBeautyWithType:(FILTER_TYPE)type {
  289. switch (type) {
  290. case FILTER_TYPE_NONE:
  291. return RCRTCBeautyFilterNone;
  292. case FILTER_TYPE_QINGXIN:
  293. return RCRTCBeautyFilterFresh;
  294. case FILTER_TYPE_WEIMEI:
  295. return RCRTCBeautyFilterEsthetic;
  296. case FILTER_TYPE_LANGMAN:
  297. return RCRTCBeautyFilterRomantic;
  298. default:
  299. return RCRTCBeautyFilterNone;
  300. break;
  301. }
  302. }
  303. - (void)configSettingBeauty:(BOOL)isOn white:(NSInteger)whitenessLevel smoothLevel:(NSInteger)smoothLevel ruddyLevel:(NSInteger)ruddyLevel brightLevel:(NSInteger)brightLevel filter:(RCRTCBeautyFilter)filter filterLevel:(int)filterLevel {
  304. self.isBeautyOn = isOn;
  305. if (isOn) {
  306. // 获取当前美颜参数
  307. RCRTCBeautyOption *option = [[RCRTCBeautyEngine sharedInstance] getCurrentBeautyOption];
  308. // 修改参数
  309. option.whitenessLevel = whitenessLevel;
  310. option.smoothLevel = smoothLevel;
  311. option.ruddyLevel = ruddyLevel;
  312. option.brightLevel = brightLevel;
  313. // 设置美颜
  314. [[RCRTCBeautyEngine sharedInstance] setBeautyOption:isOn option:option];
  315. // 设置滤镜
  316. [[RCRTCBeautyEngine sharedInstance] setBeautyFilter:filter];
  317. // 设置滤镜强度
  318. [[RCRTCBeautyEngine sharedInstance] setFilterIntensity:filterLevel];
  319. }
  320. else {
  321. [[RCRTCBeautyEngine sharedInstance] reset];
  322. }
  323. }
  324. - (void)showLiveView {
  325. if (self.isPauseLive) { // 直接切换页面
  326. // self.micEnable = self.micEnable;
  327. self.pageType = LIVEPAGE_LIVE;
  328. [self.view addSubview:self.livePageView];
  329. [self.livePageView mas_makeConstraints:^(MASConstraintMaker *make) {
  330. make.left.right.top.bottom.mas_equalTo(self.view);
  331. }];
  332. // 开启推流
  333. [self startPublishStream];
  334. }
  335. else {
  336. [self showhud];
  337. MJWeakSelf;
  338. [KSEnterLiveroomManager queryLiveroomConfig:self.roomId callback:^(NSDictionary * _Nullable parm) {
  339. [weakSelf removehub];
  340. if (parm != nil) {
  341. [weakSelf setupLiveroomConfig:parm];
  342. [weakSelf createLivePageViewDisplay];
  343. }
  344. }];
  345. }
  346. }
  347. - (void)startPublishStream {
  348. self.pageType = LIVEPAGE_LIVE;
  349. self.isPauseLive = NO;
  350. [self publishLocalStream];
  351. }
  352. - (void)setupLiveroomConfig:(NSDictionary *)source {
  353. NSLog(@"room config----- %@",source);
  354. self.liveRoleType = RCRTCLiveRoleTypeBroadcaster;
  355. self.createrId = [source ks_stringValueForKey:@"speakerId"];
  356. self.createrName = [source ks_stringValueForKey:@"speakerName"];
  357. self.createrAvatal = [source ks_stringValueForKey:@"speakerPic"];
  358. self.likeCount = [source ks_integerValueForKey:@"likeNum"]; // 点赞数
  359. NSInteger lookCount = [source ks_integerValueForKey:@"lookNum"];
  360. self.totalCount = lookCount; // 观看人数
  361. self.enableSeat = ![source ks_boolValueForKey:@"whether_mic"];
  362. BOOL isTemp = [[source ks_stringValueForKey:@"roomType"] isEqualToString:@"TEMP"];
  363. self.isTempRoom = isTemp;
  364. if (isTemp == NO) {
  365. self.liveEndTime = [source ks_stringValueForKey:@"liveEndTime"];
  366. self.expiredCloseMinute = [source ks_integerValueForKey:@"expiredCloseMinute"];
  367. }
  368. else {
  369. self.liveEndTime = [source ks_stringValueForKey:@"liveEndTime"];
  370. self.expiredCloseMinute = 0;
  371. }
  372. }
  373. - (void)createLivePageViewDisplay {
  374. self.micEnable = YES;
  375. self.pageType = LIVEPAGE_LIVE;
  376. self.isImConnected = [USER_MANAGER checkIMConnected];
  377. [self registerNotification];
  378. [self setupUI];
  379. [self configIMConnect];
  380. [self startTimer];
  381. }
  382. #pragma mark --- settingView
  383. - (KSBeautySettingView *)settingView {
  384. if (!_settingView) {
  385. _settingView = [KSBeautySettingView shareInstance];
  386. MJWeakSelf;
  387. [_settingView hiddenViewCallback:^{
  388. [weakSelf displayBottomView:NO];
  389. }];
  390. }
  391. return _settingView;
  392. }
  393. - (void)displayBottomView:(BOOL)isHidden {
  394. if (isHidden) {
  395. self.previewPageView.functionView.hidden = YES;
  396. }
  397. else {
  398. self.previewPageView.functionView.hidden = NO;
  399. }
  400. }
  401. #pragma mark ------- Live page
  402. - (void)startTimer {
  403. if (self.timer) {
  404. dispatch_resume(self.timer);
  405. }
  406. }
  407. - (void)registerNotification {
  408. [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(IMConnetedCallback) name:@"RongIMConnected" object:nil];
  409. [KSChatroomMessageCenter registerMessageTypes];
  410. [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didReceiveMessageNotification:) name:OnReceiveChatroomMessageNotification object:nil];
  411. [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(appEnterBackground) name:@"appEnterBackground" object:nil];
  412. [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(appBecomeActive) name:@"appBecomeActive" object:nil];
  413. [self configTimerManager];
  414. }
  415. - (void)configTimerManager {
  416. self.timeManager.endClassTime = self.liveEndTime;
  417. self.timeManager.autoCloseNetworkRoomTime = [self getCloseTime];
  418. self.timeManager.isTempRoom = self.isTempRoom;
  419. }
  420. #pragma mark ------ enter back ground
  421. - (void)appEnterBackground {
  422. self.isEnterBackground = YES;
  423. if (self.isPauseLive == NO) { // 暂停推流
  424. [self pauseLiveActionBack:NO];
  425. }
  426. }
  427. - (void)appBecomeActive {
  428. if (self.isEnterBackground && self.pageType == LIVEPAGE_LIVE && self.isOtherLogin == NO) {
  429. if ([USER_MANAGER checkIMConnected]) {
  430. // 开启推流
  431. [self startPublishStream];
  432. }
  433. else {
  434. self.needPublishStream = YES;
  435. }
  436. }
  437. self.isEnterBackground = NO;
  438. }
  439. - (void)setupUI {
  440. CGSize size = self.view.bounds.size;
  441. [self.view addSubview:self.livePageView];
  442. [self.livePageView mas_makeConstraints:^(MASConstraintMaker *make) {
  443. make.left.right.top.bottom.mas_equalTo(self.view);
  444. }];
  445. [self.livePageView addSubview:self.liveVideoView];
  446. [self.liveVideoView mas_makeConstraints:^(MASConstraintMaker *make) {
  447. make.left.top.bottom.right.mas_equalTo(self.livePageView);
  448. }];
  449. [self.livePageView addSubview:self.headView];
  450. [self.headView mas_makeConstraints:^(MASConstraintMaker *make) {
  451. make.left.right.mas_equalTo(self.livePageView);
  452. make.height.mas_equalTo(90);
  453. if (@available(iOS 11.0, *)) {
  454. make.top.mas_equalTo(self.livePageView.mas_safeAreaLayoutGuideTop).offset(10);
  455. } else {
  456. // Fallback on earlier versions
  457. make.top.mas_equalTo(self.livePageView.mas_top).offset(10);
  458. }
  459. }];
  460. [self.livePageView addSubview:self.messageContentView];
  461. [self.livePageView addSubview:self.bottomView];
  462. self.headView.boardcastName.text = [NSString returnNoNullStringWithString:self.createrName];
  463. if (![NSString isEmptyString:self.createrAvatal]) {
  464. [self.headView.boardcastAvatal sd_setImageWithURL:[NSURL URLWithString:[self.createrAvatal getUrlEndcodeString]] placeholderImage:[UIImage imageNamed:@"teacher_logo"]];
  465. }
  466. [self countLikeMessageCount];
  467. [self.headView mas_makeConstraints:^(MASConstraintMaker *make) {
  468. make.left.right.mas_equalTo(self.livePageView);
  469. make.height.mas_equalTo(90);
  470. if (@available(iOS 11.0, *)) {
  471. make.top.mas_equalTo(self.livePageView.mas_safeAreaLayoutGuideTop).offset(10);
  472. } else {
  473. // Fallback on earlier versions
  474. make.top.mas_equalTo(self.livePageView.mas_top).offset(10);
  475. }
  476. }];
  477. [self.livePageView addSubview:self.messageContentView];
  478. [self.livePageView addSubview:self.bottomView];
  479. [self.bottomView mas_makeConstraints:^(MASConstraintMaker *make) {
  480. make.left.right.mas_equalTo(self.livePageView);
  481. if (@available(iOS 11.0, *)) {
  482. make.bottom.mas_equalTo(self.livePageView.mas_safeAreaLayoutGuideBottom).offset(-5);
  483. } else {
  484. // Fallback on earlier versions
  485. make.bottom.mas_equalTo(self.livePageView.mas_bottom).offset(-5);
  486. }
  487. make.height.mas_equalTo(44);
  488. }];
  489. [self.messageContentView mas_makeConstraints:^(MASConstraintMaker *make) {
  490. make.left.mas_equalTo(self.livePageView.mas_left);
  491. make.right.mas_equalTo(self.livePageView.mas_right);
  492. make.bottom.mas_equalTo(self.bottomView.mas_top).offset(-5);
  493. make.height.mas_equalTo(180);
  494. }];
  495. [self.livePageView addSubview:self.inputBar];
  496. [_inputBar setBackgroundColor: [UIColor whiteColor]];
  497. [_inputBar setFrame:CGRectMake(0, kScreenHeight, size.width , 50)];
  498. [_inputBar setHidden:YES];
  499. [self.messageContentView addSubview:self.conversationMessageTableView];
  500. [self.conversationMessageTableView mas_makeConstraints:^(MASConstraintMaker *make) {
  501. make.left.top.mas_equalTo(self.messageContentView);
  502. make.width.mas_equalTo(KPortraitWidth);
  503. make.bottom.mas_equalTo(self.messageContentView.mas_bottom);
  504. }];
  505. [self.livePageView addSubview:self.seatApplyTips];
  506. [self.seatApplyTips hideView];
  507. [self.seatApplyTips mas_makeConstraints:^(MASConstraintMaker *make) {
  508. make.bottom.mas_equalTo(self.bottomView.mas_top).offset(2);
  509. make.height.mas_equalTo(20);
  510. make.left.mas_equalTo(self.bottomView.mas_right).offset(-116);
  511. }];
  512. UITapGestureRecognizer *resetBottomTapGesture =[[UITapGestureRecognizer alloc]
  513. initWithTarget:self
  514. action:@selector(resetBottomGesture:)];
  515. resetBottomTapGesture.delegate = self;
  516. [self.livePageView addGestureRecognizer:resetBottomTapGesture];
  517. }
  518. - (void)joinChatRoom {
  519. [[RCIMClient sharedRCIMClient] joinChatRoom:self.roomId messageCount:-1 success:^{
  520. dispatch_async(dispatch_get_main_queue(), ^{
  521. [self addConstMessage];
  522. self.hasJoinRoomSuccess = YES;
  523. });
  524. } error:^(RCErrorCode status) {
  525. if (status == RC_CHATROOM_NOT_EXIST || status == KICKED_FROM_CHATROOM || status == RC_PARAMETER_INVALID_CHATROOM) {
  526. dispatch_async(dispatch_get_main_queue(), ^{
  527. [self MBPShow:@"加入聊天室失败"];
  528. });
  529. }
  530. }];
  531. }
  532. - (void)configIMConnect {
  533. if (self.isImConnected == YES) {
  534. [self connectionService];
  535. }
  536. else {
  537. MJWeakSelf;
  538. [USER_MANAGER connectionIMCallback:^(BOOL isSuccess) {
  539. dispatch_main_async_safe(^{
  540. [weakSelf connectionService];
  541. });
  542. }];
  543. }
  544. }
  545. - (void)IMConnetedCallback {
  546. dispatch_main_async_safe(^{
  547. // IM 连接成功回调
  548. if (self.hasJoinRoomSuccess) { // 如果已经发送了进入消息
  549. // 查询是否直播间开启
  550. [KSNetworkingManager speakerCheckRoomInfoRequest:KS_GET roomUid:self.roomId success:^(NSDictionary * _Nonnull dic) {
  551. if ([dic ks_integerValueForKey:@"code"] == 200 && [dic ks_boolValueForKey:@"status"]) {
  552. // 回调信息
  553. MJWeakSelf;
  554. [self notiferJoinSuccessToServiceCallback:^{
  555. [weakSelf MBPShow:@"IM连接成功"];
  556. [weakSelf joinChatRoomAndLiveRoom];
  557. }];
  558. }
  559. else {
  560. [self MBPShow:MESSAGEKEY];
  561. [self quitRoomBackPreView:NO];
  562. }
  563. } faliure:^(NSError * _Nonnull error) {
  564. }];
  565. }
  566. if (self.needPublishStream) {
  567. [self startPublishStream];
  568. }
  569. });
  570. }
  571. - (void)joinChatRoomAndLiveRoom {
  572. [[RCIMClient sharedRCIMClient] joinExistChatRoom:self.roomId messageCount:-1 success:^{
  573. MJWeakSelf;
  574. [self leaveRTCRoomCallback:^(BOOL success) {
  575. dispatch_main_async_safe(^{
  576. [weakSelf joinRTCRoom];
  577. });
  578. }];
  579. } error:^(RCErrorCode status) {
  580. NSLog(@"error code %zd" ,status);
  581. }];
  582. }
  583. - (void)leaveRTCRoomCallback:(void(^)(BOOL success))callback {
  584. [[RCRTCEngine sharedInstance] leaveRoom:^(BOOL isSuccess, RCRTCCode code) {
  585. callback(isSuccess);
  586. }];
  587. }
  588. - (void)joinRTCRoom {
  589. [self setRoleType];
  590. }
  591. - (void)liveroomLogOut {
  592. if (self.isOtherLogin) {
  593. return;
  594. }
  595. self.isOtherLogin = YES;
  596. [self MBPShow:@"该账号在其他设备上登录"];
  597. [self quitRoomBackPreView:NO];
  598. dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.5f * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
  599. [[NSNotificationCenter defaultCenter] postNotificationName:@"liveroomBackRefresh" object:nil];
  600. });
  601. }
  602. - (void)liveroomQuit {
  603. if (self.isOtherLogin) {
  604. return;
  605. }
  606. self.isOtherLogin = YES;
  607. [self quitRoomBackPreView:NO];
  608. dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.0f * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
  609. [[NSNotificationCenter defaultCenter] postNotificationName:@"liveroomBackRefresh" object:nil];
  610. });
  611. }
  612. - (void)connectionService {
  613. [self joinChatRoom];
  614. [self setRoleType];
  615. }
  616. - (void)countLikeMessageCount {
  617. NSInteger count = self.likeCount;
  618. NSString *desc = @"";
  619. if (count > 10000) {
  620. count = count / 10000;
  621. desc = [NSString stringWithFormat:@"本场点赞%zd万+",count];
  622. }
  623. else {
  624. desc = [NSString stringWithFormat:@"本场点赞%zd",count];
  625. }
  626. self.headView.likeCount.text = desc;
  627. }
  628. - (void)countMemberCount {
  629. NSInteger count = self.totalCount;
  630. NSString *desc = @"";
  631. if (count > 10000) {
  632. count = count / 10000;
  633. desc = [NSString stringWithFormat:@"%zd万+人",count];
  634. }
  635. else {
  636. desc = [NSString stringWithFormat:@"%zd人",count];
  637. }
  638. self.headView.roomMemberCount.text = desc;
  639. }
  640. // 刷新seatView
  641. - (void)renderSeatView {
  642. NSMutableArray *seatArray = [NSMutableArray array];
  643. NSArray *remoteUserArray = [self.room.remoteUsers mutableCopy];
  644. for (RCRTCRemoteUser *user in remoteUserArray) {
  645. if (![user.userId containsString:@"rc_mc_"]) {
  646. [seatArray addObject:user.userId];
  647. }
  648. }
  649. if (seatArray.count) {
  650. if (![self.livePageView.subviews containsObject:self.seatContainer]) {
  651. [self.livePageView addSubview:self.seatContainer];
  652. }
  653. [self.seatContainer mas_remakeConstraints:^(MASConstraintMaker *make) {
  654. make.left.right.mas_equalTo(self.livePageView);
  655. make.top.mas_equalTo(self.headView.mas_bottom).offset(10);
  656. make.height.mas_equalTo(80);
  657. }];
  658. self.seatContainer.seatMemberArray = [NSMutableArray arrayWithArray:seatArray];
  659. [self.seatContainer refreshSeatUI];
  660. [self refreshSeatApplyList];
  661. }
  662. else {
  663. [self removeSeatContainer];
  664. }
  665. }
  666. - (void)refreshSeatApplyList {
  667. // 查询不在列表的成员
  668. NSMutableArray *requestArray = [NSMutableArray array];
  669. NSMutableArray *memberArray = [self.seatContainer.seatMemberArray mutableCopy];
  670. NSMutableArray *seatApplyArray = [self.seatApplyArray mutableCopy];
  671. for (NSString *userId in memberArray) {
  672. BOOL containUser = NO;
  673. for (LiveSeatMember *member in seatApplyArray) {
  674. if ([member.userId isEqualToString:userId]) {
  675. containUser = YES;
  676. }
  677. }
  678. if (containUser == NO) {
  679. LiveSeatMember *member = [[LiveSeatMember alloc] init];
  680. member.isConnected = YES;
  681. member.userId = userId;
  682. [requestArray addObject:member];
  683. }
  684. }
  685. if (requestArray.count) {
  686. self.seatApplyArray = [NSMutableArray arrayWithArray:requestArray];
  687. [self refreshSeatApplyView];
  688. }
  689. }
  690. - (void)removeSeatContainer {
  691. if ([self.livePageView.subviews containsObject:self.seatContainer]) {
  692. [self.seatContainer removeFromSuperview];
  693. }
  694. }
  695. - (void)setRoleType {
  696. // 1.设置切换听筒为扬声器
  697. [[RCRTCEngine sharedInstance] setDefaultAudioRouteToSpeaker:YES];
  698. [RCRTCEngine sharedInstance].statusReportDelegate = self;
  699. // 2.添加本地采集预览界面
  700. [self setupLocalVideoView];
  701. // 3.加入RTC房间
  702. [self joinRTCLiveRoom];
  703. }
  704. // 添加本地采集预览页面
  705. - (void)setupLocalVideoView {
  706. [self.liveVideoView addSubview:self.localVideo.canvesView];
  707. [self.localVideo.canvesView mas_makeConstraints:^(MASConstraintMaker *make) {
  708. make.left.right.top.bottom.mas_equalTo(self.liveVideoView);
  709. }];
  710. }
  711. #pragma mark ----- RCRTCStatusReportDelegate
  712. - (void)didReportStatusForm:(RCRTCStatusForm *)form {
  713. BOOL isConnectedFailed = NO;
  714. for (RCRTCStreamStat* stat in form.sendStats) {
  715. if (stat.packetLoss == 1.0) {
  716. isConnectedFailed = YES;
  717. break;
  718. }
  719. }
  720. [self showNetStatus:form.rtt networkLost:isConnectedFailed];
  721. // NSLog(@"%@",form.description);
  722. // 网络状态差提示
  723. }
  724. - (void)showNetStatus:(NSInteger)rttValue networkLost:(BOOL)isFailed {
  725. dispatch_main_async_safe((^{
  726. if (isFailed) {
  727. [self.headView.rttImage setImage:[UIImage imageNamed:@"live_networking_bad"]];
  728. self.headView.msLabel.text = @"网络已断开";
  729. }
  730. else {
  731. self.headView.msLabel.text = [NSString stringWithFormat:@"%zdms",rttValue];
  732. if (rttValue < 100) {
  733. [self.headView.rttImage setImage:[UIImage imageNamed:@"live_networking_good"]];
  734. }
  735. else if (rttValue < 200) {
  736. [self.headView.rttImage setImage:[UIImage imageNamed:@"live_networking_nomal"]];
  737. }
  738. else {
  739. [self.headView.rttImage setImage:[UIImage imageNamed:@"live_networking_bad"]];
  740. }
  741. }
  742. }));
  743. }
  744. #pragma mark ---- RCRTCRoomEventDelegate
  745. // 远端发布流
  746. - (void)didPublishStreams:(NSArray<RCRTCInputStream *> *)streams {
  747. [self subscribeRemoteResource:streams];
  748. NSLog(@"didPublishStreams --------");
  749. }
  750. // 订阅远端流
  751. - (void)subscribeRemoteResource:(NSArray<RCRTCInputStream *> *)streams {
  752. [self subscribeRemoteResource:streams isTiny:NO];
  753. }
  754. - (void)subscribeRemoteResource:(NSArray<RCRTCInputStream *> *)streams isTiny:(BOOL)isTiny {
  755. // 订阅房间中远端用户音视频流资源
  756. NSArray *tinyStream = isTiny ? streams : @[];
  757. NSArray *ordinaryStream = isTiny ? @[] : streams;
  758. MJWeakSelf;
  759. [self.room.localUser subscribeStream:ordinaryStream
  760. tinyStreams:tinyStream
  761. completion:^(BOOL isSuccess, RCRTCCode desc) {
  762. if (desc != RCRTCCodeSuccess) {
  763. NSString *errorStr = [NSString stringWithFormat:@"订阅远端流失败:%ld", (long) desc];
  764. [weakSelf MBPShow:errorStr];
  765. return;
  766. }
  767. }];
  768. [self renderSeatView];
  769. }
  770. - (void)didUnpublishStreams:(NSArray<RCRTCInputStream *> *)streams {
  771. NSLog(@"didUnPublishStreams --------");
  772. [self renderSeatView];
  773. }
  774. - (void)didOfflineUser:(RCRTCRemoteUser *)user {
  775. [self renderSeatView];
  776. }
  777. - (void)didJoinUser:(RCRTCRemoteUser *)user {
  778. NSLog(@"--didJoinUser-");
  779. // [self renderSeatView];
  780. }
  781. // 如果有远端用户离开房间
  782. - (void)didLeaveUser:(RCRTCRemoteUser *)user {
  783. NSLog(@"--didLeaveUser-");
  784. // 如果有人离开房间
  785. if ([self judgeContainMember:user.userId]) {
  786. [self removeMember:user.userId];
  787. [self refreshSeatApplyView];
  788. }
  789. [self renderSeatView];
  790. }
  791. // 远端用户切换身份
  792. - (void)didSwitchRoleWithUser:(RCRTCRemoteUser *)user roleType:(RCRTCLiveRoleType)roleType {
  793. if (roleType == RCRTCLiveRoleTypeBroadcaster) {
  794. if ([self judgeContainUser:user.userId] == NO) {
  795. [self.remoteMemberArray addObject:user];
  796. // 刷新连麦成员状态数据
  797. if ([self judgeContainMember:user.userId]) {
  798. // 更新状态
  799. [self updateMemberStatusConnecting:user.userId];
  800. [self refreshSeatApplyView];
  801. }
  802. }
  803. }
  804. else {
  805. [self removeMemberUserId:user.userId];
  806. // 刷新连麦成员数据
  807. if ([self judgeContainMember:user.userId]) {
  808. [self removeMember:user.userId];
  809. [self refreshSeatApplyView];
  810. }
  811. [self renderSeatView];
  812. }
  813. NSLog(@"didSwitchRoleWithUser --------");
  814. }
  815. - (BOOL)judgeContainUser:(NSString *)userId {
  816. BOOL containUser = NO;
  817. for (RCRTCRemoteUser *remoteUser in self.remoteMemberArray) {
  818. if ([remoteUser.userId isEqualToString:userId]) {
  819. containUser = YES;
  820. }
  821. }
  822. return containUser;
  823. }
  824. - (BOOL)getUserConnectStatus:(NSString *)userId {
  825. BOOL isConnected = NO;
  826. for (LiveSeatMember *member in self.seatApplyArray) {
  827. if ([member.userId isEqualToString:userId]) {
  828. return member.isConnected;
  829. }
  830. }
  831. return isConnected;
  832. }
  833. - (void)removeMemberUserId:(NSString *)userId {
  834. for (RCRTCRemoteUser *remoteUser in self.remoteMemberArray) {
  835. if ([remoteUser.userId isEqualToString:userId]) {
  836. [self.remoteMemberArray removeObject:remoteUser];
  837. return;
  838. }
  839. }
  840. }
  841. #pragma mark - KSChatInputBarControlDelegate
  842. // 根据inputBar 回调来修改页面布局
  843. - (void)onInputBarControlContentSizeChanged:(CGRect)frame withAnimationDuration:(CGFloat)duration andAnimationCurve:(UIViewAnimationCurve)curve {
  844. CGRect originFrame = _inputBar.frame;
  845. __weak __typeof(&*self)weakSelf = self;
  846. // 目前只使用y值即可 -- 只修改messageContentView高度,让展示消息view和输入框随之移动
  847. [UIView animateWithDuration:duration animations:^{
  848. [UIView setAnimationCurve:curve];
  849. [weakSelf.inputBar setFrame:CGRectMake(0, frame.origin.y - originFrame.size.height, originFrame.size.width, originFrame.size.height)];
  850. [UIView commitAnimations];
  851. }];
  852. }
  853. // 发送消息
  854. - (void)onTouchSendButton:(NSString *)text {
  855. [self touristSendMessage:text];
  856. }
  857. - (void)touristSendMessage:(NSString *)text {
  858. RCTextMessage *rcTextMessage = [RCTextMessage messageWithContent:text];
  859. MJWeakSelf;
  860. [self sendMessage:rcTextMessage displayMessage:YES callback:^(BOOL success) {
  861. [weakSelf setDefaultBottomViewStatus];
  862. }];
  863. }
  864. #pragma mark ---- RTC
  865. - (void)joinRTCLiveRoom {
  866. // 1.配置房间
  867. RCRTCRoomConfig *config = [[RCRTCRoomConfig alloc] init];
  868. config.roomType = RCRTCRoomTypeLive;
  869. config.liveType = RCRTCLiveTypeAudioVideo;
  870. config.roleType = RCRTCLiveRoleTypeBroadcaster;
  871. __weak typeof(self) weakSelf = self;
  872. [[RCRTCEngine sharedInstance] joinRoom:self.roomId config:config completion:^(RCRTCRoom * _Nullable room, RCRTCCode code) {
  873. dispatch_main_async_safe(^{
  874. __strong typeof(weakSelf) strongSelf = weakSelf;
  875. if (code == RCRTCCodeSignalServerNotConnect || code == RCRTCCodeParameterError || code == RCRTCCodeNotInRTCRoom || code == RCRTCCodeRTCTokenIsNull || code == RCRTCCodeHttpTimeoutError || code == RCRTCCodeHttpError || code == RCRTCCodeVoIPNotAvailable) {
  876. NSLog(@"%@",[NSString stringWithFormat:@"加入失败 code %ld",code]);
  877. [strongSelf MBPShow:@"加入直播间失败"];
  878. }
  879. else {
  880. [strongSelf notiferJoinSuccessToServiceCallback:^{
  881. }];
  882. if (room) {
  883. strongSelf.room = room;
  884. strongSelf.room.delegate = self;
  885. if (room.remoteUsers.count) {
  886. NSMutableArray *streamArray = [NSMutableArray array];
  887. NSMutableArray *remoteUserArray = [room.remoteUsers mutableCopy];
  888. for (RCRTCRemoteUser *user in remoteUserArray) {
  889. if (user.remoteStreams.count) {
  890. [streamArray addObjectsFromArray:user.remoteStreams];
  891. }
  892. }
  893. // 如果存在远端流 订阅
  894. if (streamArray.count) {
  895. [strongSelf subscribeRemoteResource:streamArray];
  896. }
  897. }
  898. }
  899. // 订阅流数据
  900. [strongSelf renderSeatView];
  901. [strongSelf countMemberCount];
  902. // 发布本地视频流
  903. if (strongSelf.isPauseLive == NO && strongSelf.isEnterBackground == NO) {
  904. [strongSelf publishLocalStream];
  905. }
  906. }
  907. });
  908. }];
  909. }
  910. - (void)publishLocalStream {
  911. // 1.设置渲染视图渲染视图
  912. [[RCRTCEngine sharedInstance].defaultVideoStream setVideoView:self.localVideo.canvesView];
  913. // 2.设置视频流参数
  914. RCRTCVideoStreamConfig *videoConfig = [RCRTCEngine sharedInstance].defaultVideoStream.videoConfig;
  915. videoConfig.videoSizePreset = RCRTCVideoSizePreset1280x720;
  916. videoConfig.videoFps = RCRTCVideoFPS30;
  917. videoConfig.maxBitrate = 2200;
  918. videoConfig.minBitrate = 200;
  919. [[RCRTCEngine sharedInstance].defaultVideoStream setVideoConfig:videoConfig];
  920. // 3.开始视频采集
  921. [[RCRTCEngine sharedInstance].defaultVideoStream startCapture];
  922. [RCRTCEngine sharedInstance].defaultVideoStream.enableTinyStream = NO;
  923. [[RCRTCEngine sharedInstance].defaultAudioStream setAudioQuality:RCRTCAudioQualityMusicHigh Scenario:RCRTCAudioScenarioMusicChatRoom];
  924. // 发布本地视频流到房间
  925. MJWeakSelf;
  926. [self.room.localUser publishDefaultLiveStreams:^(BOOL isSuccess, RCRTCCode code, RCRTCLiveInfo * _Nullable liveInfo) {
  927. if (code == RCRTCCodeSuccess) {
  928. weakSelf.needPublishStream = NO;
  929. [weakSelf renderSeatView];
  930. }
  931. }];
  932. }
  933. - (void)exitRoomCallback:(void(^)(BOOL success))callback {
  934. [[RCRTCEngine sharedInstance].defaultVideoStream stopCapture];
  935. _localVideo = nil;
  936. _preVideoView = nil;
  937. _room = nil;
  938. MJWeakSelf;
  939. [[RCRTCEngine sharedInstance] leaveRoom:^(BOOL isSuccess, RCRTCCode code) {
  940. NSLog(@"----- leave code -----%zd",code);
  941. dispatch_main_async_safe(^{
  942. [weakSelf sendLeaveMessageCallback:^(BOOL success) {
  943. callback(success);
  944. }];
  945. });
  946. }];
  947. }
  948. - (void)uninitEngine {
  949. [[RCRTCEngine sharedInstance] unInit];
  950. }
  951. // 销毁房间
  952. - (void)distoryRoomCallback:(void(^)(BOOL success))callback {
  953. [[RCRTCEngine sharedInstance].defaultVideoStream stopCapture];
  954. _localVideo = nil;
  955. _preVideoView = nil;
  956. _room = nil;
  957. __weak typeof(self) weakSelf = self;
  958. [[RCRTCEngine sharedInstance] leaveRoom:^(BOOL isSuccess, RCRTCCode code) {
  959. dispatch_main_async_safe(^{
  960. __strong typeof(weakSelf) strongSelf = weakSelf;
  961. [strongSelf sendLeaveMessageCallback:^(BOOL success) {
  962. callback(success);
  963. }];
  964. });
  965. }];
  966. }
  967. #pragma mark -- 加入直播间和退出直播间回到服务
  968. - (void)notiferJoinSuccessToServiceCallback:(void(^)(void))callback {
  969. [KSNetworkingManager liveRoomJoinRoomRequest:KS_GET roomUid:self.roomId success:^(NSDictionary * _Nonnull dic) {
  970. callback();
  971. } faliure:^(NSError * _Nonnull error) {
  972. callback();
  973. }];
  974. }
  975. #pragma mark -- 退出直播间回掉服务
  976. - (void)quitNotiferService {
  977. [KSNetworkingManager LiveroomQuit:KS_POST success:^(NSDictionary * _Nonnull dic) {
  978. if ([dic ks_integerValueForKey:@"errCode"] == 0) {
  979. NSLog(@"success");
  980. }
  981. else {
  982. NSLog(@"----- error %@", [dic ks_stringValueForKey:@"errMsg"]);
  983. }
  984. } faliure:^(NSError * _Nonnull error) {
  985. }];
  986. }
  987. - (void)closeRoomNotiferService {
  988. [KSNetworkingManager destroyLiveRoomRequest:KS_GET roomUid:self.roomId success:^(NSDictionary * _Nonnull dic) {
  989. if ([dic ks_integerValueForKey:@"errCode"] == 0) {
  990. NSLog(@"success");
  991. }
  992. else {
  993. NSLog(@"----- error %@", [dic ks_stringValueForKey:@"errMsg"]);
  994. }
  995. } faliure:^(NSError * _Nonnull error) {
  996. }];
  997. }
  998. - (void)sendLeaveMessageCallback:(void(^)(BOOL success))callback {
  999. RCUserInfo *currentUserInfo = [RCIM sharedRCIM].currentUserInfo;
  1000. KSLiveChatroomLeave *leaveMessage = [[KSLiveChatroomLeave alloc] init];
  1001. leaveMessage.userId = currentUserInfo.userId;
  1002. leaveMessage.userName = currentUserInfo.name;
  1003. [self sendMessage:leaveMessage displayMessage:NO callback:^(BOOL success) {
  1004. callback(success);
  1005. }];
  1006. }
  1007. - (void)quitChatRoom {
  1008. [[RCIMClient sharedRCIMClient] quitChatRoom:self.roomId success:^{
  1009. NSLog(@"sucess log out--");
  1010. } error:^(RCErrorCode status) {
  1011. NSLog(@"RCErrorCode------%ld ", (long)status);
  1012. }];
  1013. }
  1014. - (void)addConstMessage { // 固定欢迎词语
  1015. RCTextMessage *statement = [RCTextMessage messageWithContent:@"欢迎进入直播课堂,请遵守相关法规,禁止传播低俗、暴力等不良信息。为孩子创造健康绿色的学习环境。"];
  1016. statement.extra = @"statement";
  1017. RCMessage *constMessage = [[RCMessage alloc] initWithType:ConversationType_CHATROOM targetId:self.roomId direction:MessageDirection_SEND content:statement];
  1018. constMessage.content.senderUserInfo = [RCIM sharedRCIM].currentUserInfo;
  1019. [self appendAndDisplayMessage:constMessage];
  1020. }
  1021. #pragma mark - views init
  1022. /**
  1023. * 接收到消息的回调
  1024. */
  1025. - (void)didReceiveMessageNotification:(NSNotification *)notification {
  1026. NSDictionary *dic = notification.object;
  1027. __block RCMessage *rcMessage = dic[@"message"];
  1028. KSRCMessageModel *model = [[KSRCMessageModel alloc] initWithMessage:rcMessage];
  1029. model.userInfo = rcMessage.content.senderUserInfo;
  1030. if (model.conversationType == ConversationType_CHATROOM && [model.targetId isEqualToString:self.roomId]) {
  1031. __weak typeof(&*self) __blockSelf = self;
  1032. dispatch_main_async_safe((^{
  1033. // 对赞消息拦截 ,展示动画,不插入数据源 ,对于seat消息 和踢出消息,弹出alert
  1034. if (rcMessage) {
  1035. // 👍🏻消息
  1036. if ([rcMessage.content isMemberOfClass:[KSLiveChatroomLike class]]) {
  1037. KSLiveChatroomLike *likeMessage = (KSLiveChatroomLike *)rcMessage.content;
  1038. // 统计点赞数量
  1039. __blockSelf.likeCount += likeMessage.counts;
  1040. [__blockSelf countLikeMessageCount];
  1041. }
  1042. else if ([rcMessage.content isMemberOfClass:[KSLiveChatroomWelcome class]]) {
  1043. // 过滤自己发送的欢迎消息
  1044. if ([rcMessage.senderUserId isEqualToString:UserDefault(UIDKey)]) {
  1045. return;
  1046. }
  1047. // 弹幕
  1048. RCUserInfo *userInfo = rcMessage.content.senderUserInfo;
  1049. NSString *userName = [userInfo.name stringByAppendingString:@""];
  1050. NSString *contentMsg = [NSString stringWithFormat:@"%@ 进入直播间",userName];
  1051. [__blockSelf showAnimationView:YES showMessag:contentMsg];
  1052. if ([__blockSelf judgeContainMember:rcMessage.senderUserId]) {
  1053. [__blockSelf removeMember:rcMessage.senderUserId];
  1054. [__blockSelf refreshSeatApplyView];
  1055. [__blockSelf renderSeatView];
  1056. }
  1057. }
  1058. else if ([rcMessage.content isMemberOfClass:[KSLiveChatroomMemberUp class]]) {
  1059. KSLiveChatroomMemberUp *member = (KSLiveChatroomMemberUp *)rcMessage.content;
  1060. __blockSelf.totalCount = member.count;
  1061. [__blockSelf countMemberCount];
  1062. }
  1063. // 用户退出消息
  1064. else if ([rcMessage.content isMemberOfClass:[KSLiveChatroomLeave class]]) {
  1065. KSLiveChatroomLeave *memberLeaveMsg = (KSLiveChatroomLeave *)rcMessage.content;
  1066. if ([__blockSelf judgeContainMember:memberLeaveMsg.userId]) {
  1067. [__blockSelf removeMember:memberLeaveMsg.userId];
  1068. [__blockSelf refreshSeatApplyView];
  1069. }
  1070. return;
  1071. }
  1072. // 连麦申请消息
  1073. else if ([rcMessage.content isMemberOfClass:[KSLiveChatroomSeatApply class]]) {
  1074. KSLiveChatroomSeatApply *seatApplyMessage = (KSLiveChatroomSeatApply *)rcMessage.content;
  1075. if (seatApplyMessage.type == SEATHANDLE_APPLY) { // 观众申请 加入申请中
  1076. LiveSeatMember *member = [[LiveSeatMember alloc] init];
  1077. member.avatar = seatApplyMessage.audienceAvatar;
  1078. member.name = seatApplyMessage.audienceName;
  1079. member.userId = seatApplyMessage.audienceId;
  1080. member.isConnected = NO;
  1081. if (![__blockSelf judgeContainMember:member.userId]) {
  1082. [__blockSelf.seatApplyArray addObject:member];
  1083. [__blockSelf refreshSeatApplyView];
  1084. }
  1085. }
  1086. else if (seatApplyMessage.type == SEATHANDLE_CANCELAPPLY) { // 观众取消申请 从申请中剔除
  1087. if ([__blockSelf judgeContainMember:seatApplyMessage.audienceId]) {
  1088. // 如果在申请中的状态
  1089. BOOL connectedStatus = [__blockSelf getUserConnectStatus:seatApplyMessage.audienceId];
  1090. if (connectedStatus == NO) {
  1091. NSLog(@"hahahhahah");
  1092. [__blockSelf removeMember:seatApplyMessage.audienceId];
  1093. [__blockSelf refreshSeatApplyView];
  1094. }
  1095. }
  1096. }
  1097. return;
  1098. }
  1099. // 连麦回复消息(暂不处理)
  1100. else if ([rcMessage.content isMemberOfClass:[KSLiveChatroomSeatResponse class]]) {
  1101. }
  1102. else if ([rcMessage.content isMemberOfClass:[KSLiveChatroomDownSeat class]]) { // 观众下麦,从列表中移除
  1103. KSLiveChatroomDownSeat *downSeatMessage = (KSLiveChatroomDownSeat *)rcMessage.content;
  1104. if ([__blockSelf judgeContainMember:downSeatMessage.audienceId]) {
  1105. [__blockSelf removeMember:downSeatMessage.audienceId];
  1106. [__blockSelf refreshSeatApplyView];
  1107. }
  1108. return;
  1109. }
  1110. else if ([rcMessage.content isMemberOfClass:[KSRCShopRushMessage class]]) {
  1111. KSRCShopRushMessage *rushMsg = (KSRCShopRushMessage *)rcMessage.content;
  1112. NSString *contentMsg = [NSString stringWithFormat:@"%@ 正在抢购",[NSString returnNoNullStringWithString:rushMsg.userName]];
  1113. [__blockSelf showAnimationView:NO showMessag:contentMsg];
  1114. }
  1115. else if ([rcMessage.content isMemberOfClass:[RCTextMessage class]]) {
  1116. [__blockSelf insertMessage:rcMessage userInfo:notification.userInfo];
  1117. }
  1118. else if ([rcMessage.content isMemberOfClass:[KSLiveChatroomClose class]]) { // 直播间已关闭
  1119. [__blockSelf MBPShow:@"直播已结束"];
  1120. dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.0f * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
  1121. // 退出直播间
  1122. [__blockSelf quitRoomBackPreView:NO];
  1123. });
  1124. return;
  1125. }
  1126. }
  1127. }));
  1128. }
  1129. }
  1130. - (void)insertMessage:(RCMessage *)rcMessage userInfo:(NSDictionary *)userInfo {
  1131. // left
  1132. NSDictionary *leftDic = userInfo;
  1133. if (leftDic && [leftDic[@"left"] isEqual:@(0)]) {
  1134. self.isNeedScrollToButtom = YES;
  1135. }
  1136. [self appendAndDisplayMessage:rcMessage];
  1137. }
  1138. - (BOOL)judgeContainMember:(NSString *)userId {
  1139. for (LiveSeatMember *obj in self.seatApplyArray) {
  1140. if ([obj.userId isEqualToString:userId]) {
  1141. return YES;
  1142. }
  1143. }
  1144. return NO;
  1145. }
  1146. - (NSInteger)queryConnectingCount {
  1147. NSInteger count = 0;
  1148. for (LiveSeatMember *member in self.seatApplyArray) {
  1149. if (member.isConnected) {
  1150. count++;
  1151. }
  1152. }
  1153. return count;
  1154. }
  1155. - (void)removeMember:(NSString *)memberId {
  1156. for (LiveSeatMember *member in self.seatApplyArray) {
  1157. if ([member.userId isEqualToString:memberId]) {
  1158. [self.seatApplyArray removeObject:member];
  1159. return;
  1160. }
  1161. }
  1162. }
  1163. - (void)updateMemberStatusWaiting:(NSString *)userId {
  1164. for (LiveSeatMember *obj in self.seatApplyArray) {
  1165. if ([obj.userId isEqualToString:userId]) {
  1166. obj.isConnected = NO;
  1167. return;
  1168. }
  1169. }
  1170. }
  1171. - (void)updateMemberStatusConnecting:(NSString *)userId {
  1172. for (LiveSeatMember *obj in self.seatApplyArray) {
  1173. if ([obj.userId isEqualToString:userId]) {
  1174. obj.isConnected = YES;
  1175. return;
  1176. }
  1177. }
  1178. }
  1179. - (void)refreshSeatApplyView {
  1180. if (self.seatApplyArray.count) {
  1181. NSInteger count = 0;
  1182. for (LiveSeatMember *obj in self.seatApplyArray) {
  1183. if (obj.isConnected == NO) {
  1184. count++;
  1185. }
  1186. }
  1187. if (count > 0) {
  1188. [self showSeatTips:count];
  1189. }
  1190. else {
  1191. [self hideSeatTips];
  1192. }
  1193. }
  1194. else {
  1195. [self hideSeatTips];
  1196. }
  1197. [self.seatActionView refreshSeatApplyTable:self.seatApplyArray];
  1198. }
  1199. - (void)showSeatTips:(NSInteger)count {
  1200. NSString *countDesc = count >= 100 ? @"99+" : [NSString stringWithFormat:@"%zd",count];
  1201. [self.seatApplyTips configCountMessage:countDesc];
  1202. [self.seatApplyTips showTipsView];
  1203. }
  1204. - (void)hideSeatTips {
  1205. [self.seatApplyTips hideView];
  1206. }
  1207. // 发送人数同步消息
  1208. - (void)sendMemberCountMessage {
  1209. KSLiveChatroomMemberCount *syncMessage = [[KSLiveChatroomMemberCount alloc] init];
  1210. syncMessage.count = self.totalCount;
  1211. [self sendMessage:syncMessage displayMessage:NO callback:^(BOOL success) {
  1212. }];
  1213. }
  1214. #pragma mark ----- time manager delegate
  1215. - (void)formatTime:(NSString *)timeString {
  1216. self.headView.timeLabel.text = timeString;
  1217. }
  1218. - (void)timeLabelAddAnimation:(CABasicAnimation *)animation {
  1219. self.headView.timeLabel.textColor = HexRGB(0x2DC7AA);
  1220. // [self.headView.timeLabel.layer addAnimation:animation forKey:nil];
  1221. }
  1222. //- (void)quitClassroomNotifer {
  1223. // [self MBPShow:@"直播已结束!"];
  1224. // dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.5f * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
  1225. // [self quitRoomBackPreView:NO];
  1226. // });
  1227. //}
  1228. #pragma mark - gesture and button action
  1229. - (void)resetBottomGesture:(UIGestureRecognizer *)gestureRecognizer {
  1230. if (gestureRecognizer.state == UIGestureRecognizerStateEnded) {
  1231. [self setDefaultBottomViewStatus];
  1232. }
  1233. }
  1234. - (void)setDefaultBottomViewStatus {
  1235. [self.inputBar setInputBarStatus:KSBottomBarStatusDefault];
  1236. [self.inputBar setHidden:YES];
  1237. }
  1238. #pragma mark ---- sendMessage/showMessage
  1239. - (void)sendMessage:(RCMessageContent *)messageContent displayMessage:(BOOL)displayMessage callback:(void(^)(BOOL success))callback {
  1240. if (_roomId == nil) {
  1241. return;
  1242. }
  1243. messageContent.senderUserInfo = [RCIM sharedRCIM].currentUserInfo;
  1244. if (messageContent == nil) {
  1245. return;
  1246. }
  1247. __weak typeof(&*self) __weakself = self;
  1248. [KSChatroomMessageCenter sendChatMessage:self.roomId content:messageContent success:^(long messageId) {
  1249. dispatch_async(dispatch_get_main_queue(), ^{
  1250. RCMessage *message = [[RCMessage alloc] initWithType:ConversationType_CHATROOM targetId:__weakself.roomId direction:MessageDirection_SEND content:messageContent];
  1251. message.content.senderUserInfo = [RCIM sharedRCIM].currentUserInfo;
  1252. message.senderUserId = UserDefault(UIDKey);
  1253. if (displayMessage) {
  1254. [__weakself appendAndDisplayMessage:message];
  1255. }
  1256. [__weakself.inputBar clearInputView];
  1257. callback(YES);
  1258. });
  1259. } error:^(RCErrorCode errorCode, long messageId) {
  1260. if (errorCode == RC_CHATROOM_NOT_EXIST) {
  1261. dispatch_async(dispatch_get_main_queue(), ^{
  1262. [self MBPShow:@"聊天已被解散,请退出后重进。"];
  1263. });
  1264. }
  1265. dispatch_async(dispatch_get_main_queue(), ^{
  1266. [__weakself.inputBar clearInputView];
  1267. NSLog(@"发送失败,errorcode is: %ld",(long)errorCode);
  1268. callback(NO);
  1269. });
  1270. }];
  1271. }
  1272. /**
  1273. * 将消息加入本地数组
  1274. */
  1275. - (void)appendAndDisplayMessage:(RCMessage *)rcMessage {
  1276. if (!rcMessage) {
  1277. return;
  1278. }
  1279. KSRCMessageModel *model = [[KSRCMessageModel alloc] initWithMessage:rcMessage];
  1280. model.userInfo = rcMessage.content.senderUserInfo;
  1281. if (!model.userInfo) {
  1282. model.userInfo = [RCIMClient sharedRCIMClient].currentUserInfo;
  1283. }
  1284. if ([self appendMessageModel:model]) {
  1285. NSIndexPath *indexPath =
  1286. [NSIndexPath indexPathForItem:self.conversationDataRepository.count - 1
  1287. inSection:0];
  1288. if ([self.conversationMessageTableView numberOfRowsInSection:0] !=
  1289. self.conversationDataRepository.count - 1) {
  1290. return;
  1291. }
  1292. // view刷新
  1293. [self.conversationMessageTableView insertRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationNone];
  1294. if ([self isAtTheBottomOfTableView] || self.isNeedScrollToButtom) {
  1295. [self scrollToBottomAnimated:YES];
  1296. self.isNeedScrollToButtom=NO;
  1297. }
  1298. }
  1299. return;
  1300. }
  1301. /**
  1302. * 如果当前会话没有这个消息id,把消息加入本地数组
  1303. */
  1304. - (BOOL)appendMessageModel:(KSRCMessageModel *)model {
  1305. if (!model.content) {
  1306. return NO;
  1307. }
  1308. //这里可以根据消息类型来决定是否显示,如果不希望显示直接return NO
  1309. //数量不可能无限制的大,这里限制收到消息过多时,就对显示消息数量进行限制。
  1310. //用户可以手动下拉更多消息,查看更多历史消息。
  1311. if (self.conversationDataRepository.count>100) {
  1312. // NSRange range = NSMakeRange(0, 1);
  1313. KSRCMessageModel *message = self.conversationDataRepository[0];
  1314. [[RCIMClient sharedRCIMClient]deleteMessages:@[@(message.messageId)]];
  1315. [self.conversationDataRepository removeObjectAtIndex:0];
  1316. [self.conversationMessageTableView reloadData];
  1317. }
  1318. [self.conversationDataRepository addObject:model];
  1319. return YES;
  1320. }
  1321. /**
  1322. * 判断消息是否在collectionView的底部
  1323. *
  1324. * @return 是否在底部
  1325. */
  1326. - (BOOL)isAtTheBottomOfTableView {
  1327. if (self.conversationMessageTableView.contentSize.height <= self.conversationMessageTableView.frame.size.height) {
  1328. return YES;
  1329. }
  1330. if(self.conversationMessageTableView.contentOffset.y +200 >= (self.conversationMessageTableView.contentSize.height - self.conversationMessageTableView.frame.size.height)) {
  1331. return YES;
  1332. }else{
  1333. return NO;
  1334. }
  1335. }
  1336. /**
  1337. * 消息滚动到底部
  1338. *
  1339. * @param animated 是否开启动画效果
  1340. */
  1341. - (void)scrollToBottomAnimated:(BOOL)animated {
  1342. if ([self.conversationMessageTableView numberOfSections] == 0) {
  1343. return;
  1344. }
  1345. NSUInteger finalRow = MAX(0, [self.conversationMessageTableView numberOfRowsInSection:0] - 1);
  1346. if (0 == finalRow) {
  1347. return;
  1348. }
  1349. NSIndexPath *finalIndexPath =
  1350. [NSIndexPath indexPathForItem:finalRow inSection:0];
  1351. [self.conversationMessageTableView scrollToRowAtIndexPath:finalIndexPath atScrollPosition:UITableViewScrollPositionTop animated:animated];
  1352. }
  1353. /*
  1354. #pragma mark - Navigation
  1355. // In a storyboard-based application, you will often want to do a little preparation before navigation
  1356. - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
  1357. // Get the new view controller using [segue destinationViewController].
  1358. // Pass the selected object to the new view controller.
  1359. }
  1360. */
  1361. #pragma mark ----- table data source
  1362. - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
  1363. return self.conversationDataRepository.count;
  1364. }
  1365. - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
  1366. KSRCMessageModel *model = [self.conversationDataRepository objectAtIndex:indexPath.row];
  1367. RCMessageContent *messageContent = model.content;
  1368. KSChatroomTextCell *cell = [tableView dequeueReusableCellWithIdentifier:@"KSChatroomTextCell"];
  1369. if(!cell){
  1370. cell = [[KSChatroomTextCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"KSChatroomTextCell"];
  1371. }
  1372. if ([messageContent isMemberOfClass:[RCTextMessage class]] || [messageContent isMemberOfClass:[KSLiveChatroomWelcome class]] || [messageContent isMemberOfClass:[KSLiveChatroomLike class]] || [messageContent isMemberOfClass:[KSLiveChatroomSeatApply class]] || [messageContent isMemberOfClass:[KSLiveChatroomSeatResponse class]]){
  1373. [cell setDataModel:model createrId:self.createrId];
  1374. }
  1375. return cell;
  1376. }
  1377. #pragma mark --- lazying
  1378. - (UIView *)livePageView {
  1379. if (!_livePageView) {
  1380. _livePageView = [[UIView alloc] init];
  1381. _livePageView.backgroundColor = HexRGB(0x25292e);
  1382. }
  1383. return _livePageView;
  1384. }
  1385. - (UIView *)liveVideoView {
  1386. if (!_liveVideoView) {
  1387. _liveVideoView = [[UIView alloc] init];
  1388. _liveVideoView.backgroundColor = [UIColor clearColor];
  1389. }
  1390. return _liveVideoView;
  1391. }
  1392. - (LiveRoomHeadView *)headView {
  1393. if (!_headView) {
  1394. _headView = [LiveRoomHeadView shareInstance];
  1395. MJWeakSelf;
  1396. [_headView liveHeaderAction:^{
  1397. [weakSelf switchCamera];
  1398. }];
  1399. }
  1400. return _headView;
  1401. }
  1402. - (void)switchCamera {
  1403. [[RCRTCEngine sharedInstance].defaultVideoStream switchCamera];
  1404. }
  1405. - (LiveRoomBottomView *)bottomView {
  1406. if (!_bottomView) {
  1407. _bottomView = [LiveRoomBottomView shareInstance];
  1408. MJWeakSelf;
  1409. [_bottomView bottomClickAction:^(LIVEROOMACTION action) {
  1410. [weakSelf bottomViewAction:action];
  1411. }];
  1412. }
  1413. return _bottomView;
  1414. }
  1415. - (void)bottomViewAction:(LIVEROOMACTION)action {
  1416. switch (action) {
  1417. case LIVEROOMACTION_CHAT: // 聊天
  1418. {
  1419. [_inputBar setHidden:NO];
  1420. [_inputBar setInputBarStatus:KSBottomBarStatusKeyboard];
  1421. }
  1422. break;
  1423. case LIVEROOMACTION_SEAT: // 呼出连麦页面
  1424. {
  1425. [self displaySeatView];
  1426. }
  1427. break;
  1428. // case LIVEROOMACTION_QUIT: // 退出
  1429. // {
  1430. // [self showMoreView];
  1431. // }
  1432. break;
  1433. case LIVEROOMACTION_MICACTION:
  1434. {
  1435. self.micEnable = !self.micEnable;
  1436. [[RCRTCEngine sharedInstance].defaultAudioStream setMicrophoneDisable:!self.micEnable];
  1437. NSString *desc = @"";
  1438. if (self.micEnable) {
  1439. desc = @"你已开启麦克风";
  1440. }
  1441. else {
  1442. desc = @"你已关闭麦克风";
  1443. }
  1444. [self MBPShow:desc];
  1445. }
  1446. break;
  1447. default:
  1448. break;
  1449. }
  1450. }
  1451. - (void)setMicEnable:(BOOL)micEnable {
  1452. _micEnable = micEnable;
  1453. self.bottomView.isMicOn = micEnable;
  1454. }
  1455. - (void)showMoreView {
  1456. [self.view addSubview:self.moreView];
  1457. }
  1458. - (SeatTipsView *)seatApplyTips {
  1459. if (!_seatApplyTips) {
  1460. _seatApplyTips = [[SeatTipsView alloc] init];
  1461. }
  1462. return _seatApplyTips;
  1463. }
  1464. - (void)displaySeatView {
  1465. [self.view addSubview:self.seatCtrlView];
  1466. [self refreshSeatApplyView];
  1467. }
  1468. - (void)closeRoomAction {
  1469. MJWeakSelf;
  1470. self.alertView = [LiveRoomAlertView liveroomAlertWithTitle:@"结束直播后,不可再次开启" leftButtonTitle:@"取消" rightTitle:@"结束直播" inView:self.view cancel:^{
  1471. } confirm:^{
  1472. [weakSelf distoryRoomAction];
  1473. }];
  1474. }
  1475. - (void)pauseAction {
  1476. MJWeakSelf;
  1477. self.alertView = [LiveRoomAlertView liveroomAlertWithTitle:@"暂停后观众将无法看到视频画面" leftButtonTitle:@"取消" rightTitle:@"暂停直播" inView:self.view cancel:^{
  1478. } confirm:^{
  1479. [weakSelf quitRoomBackPreView:YES];
  1480. }];
  1481. }
  1482. - (void)distoryRoomAction {
  1483. MJWeakSelf;
  1484. [self distoryRoomCallback:^(BOOL success) {
  1485. [weakSelf closeRoomNotiferService];
  1486. [weakSelf quitChatRoom];
  1487. weakSelf.room = nil;
  1488. if (self.callback) {
  1489. self.callback();
  1490. }
  1491. [weakSelf.navigationController dismissViewControllerAnimated:YES completion:nil];
  1492. }];
  1493. }
  1494. - (void)pauseLiveActionBack:(BOOL)backPreView {
  1495. self.needPublishStream = NO;
  1496. KSRCPauseLiveMessage *pauseMsg = [[KSRCPauseLiveMessage alloc] init];
  1497. MJWeakSelf;
  1498. [self sendMessage:pauseMsg displayMessage:NO callback:^(BOOL success) {
  1499. if (backPreView) {
  1500. [weakSelf.moreView hideView];
  1501. weakSelf.isPauseLive = YES;
  1502. weakSelf.pageType = LIVEPAGE_PREVIEW;
  1503. [weakSelf.livePageView removeFromSuperview];
  1504. [weakSelf configEngine];
  1505. }
  1506. }];
  1507. [self.room.localUser unpublishDefaultLiveStreams:^(BOOL isSuccess, RCRTCCode code) {
  1508. if (isSuccess) {
  1509. }
  1510. }];
  1511. }
  1512. - (void)quitRoomBackPreView:(BOOL)backPreView {
  1513. if (backPreView) { // 暂停
  1514. [self pauseLiveActionBack:YES];
  1515. }
  1516. else {
  1517. if (self.pageType == LIVEPAGE_PREVIEW && self.isPauseLive == NO) {
  1518. self.room = nil;
  1519. self.preVideoView = nil;
  1520. [[RCRTCEngine sharedInstance].defaultVideoStream stopCapture];
  1521. if (self.callback) {
  1522. self.callback();
  1523. }
  1524. [self.navigationController dismissViewControllerAnimated:YES completion:nil];
  1525. }
  1526. else {
  1527. MJWeakSelf;
  1528. [self exitRoomCallback:^(BOOL success) {
  1529. // quit 接口
  1530. [weakSelf quitNotiferService];
  1531. [weakSelf quitChatRoom];
  1532. [weakSelf.moreView hideView];
  1533. if (weakSelf.callback) {
  1534. weakSelf.callback();
  1535. }
  1536. dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5f * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
  1537. [weakSelf.navigationController dismissViewControllerAnimated:YES completion:nil];
  1538. });
  1539. }];
  1540. }
  1541. }
  1542. }
  1543. - (KSLiveStreamVideo *)localVideo {
  1544. if (!_localVideo) {
  1545. _localVideo = [KSLiveStreamVideo LocalStreamVideo];
  1546. }
  1547. return _localVideo;
  1548. }
  1549. - (NSMutableArray *)remoteMemberArray {
  1550. if (!_remoteMemberArray) {
  1551. _remoteMemberArray = [NSMutableArray array];
  1552. }
  1553. return _remoteMemberArray;
  1554. }
  1555. - (UIView *)messageContentView {
  1556. if (!_messageContentView) {
  1557. _messageContentView = [[UIView alloc] init];
  1558. [_messageContentView setBackgroundColor: [UIColor clearColor]];
  1559. }
  1560. return _messageContentView;
  1561. }
  1562. - (NSMutableArray<KSRCMessageModel *> *)conversationDataRepository {
  1563. if (!_conversationDataRepository) {
  1564. _conversationDataRepository = [NSMutableArray array];
  1565. }
  1566. return _conversationDataRepository;
  1567. }
  1568. - (KSChatInputBarControl *)inputBar {
  1569. if (!_inputBar) {
  1570. _inputBar = [[KSChatInputBarControl alloc] initWithStatus:KSBottomBarStatusDefault];
  1571. [_inputBar setDelegate:self];
  1572. }
  1573. return _inputBar;
  1574. }
  1575. - (UITableView *)conversationMessageTableView {
  1576. if (!_conversationMessageTableView) {
  1577. _conversationMessageTableView = [[UITableView alloc] initWithFrame:CGRectZero style:UITableViewStylePlain];
  1578. _conversationMessageTableView.backgroundColor = [UIColor clearColor];
  1579. _conversationMessageTableView.separatorStyle = UITableViewCellSeparatorStyleNone;
  1580. _conversationMessageTableView.dataSource = self;
  1581. _conversationMessageTableView.delegate = self;
  1582. _conversationMessageTableView.rowHeight = UITableViewAutomaticDimension;
  1583. _conversationMessageTableView.estimatedRowHeight = 40.0f;
  1584. _conversationMessageTableView.showsVerticalScrollIndicator = NO;
  1585. [_conversationMessageTableView registerClass:[KSChatroomTextCell class] forCellReuseIdentifier:@"KSChatroomTextCell"];
  1586. }
  1587. return _conversationMessageTableView;
  1588. }
  1589. - (SeatContentView *)seatContainer {
  1590. if (!_seatContainer) {
  1591. _seatContainer = [[SeatContentView alloc] init];
  1592. }
  1593. return _seatContainer;
  1594. }
  1595. - (UIView *)seatCtrlView {
  1596. if (!_seatCtrlView) {
  1597. _seatCtrlView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, KPortraitWidth, KPortraitHeight)];
  1598. _seatCtrlView.backgroundColor = [UIColor clearColor];
  1599. self.gesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(hideSeatCtrlView)];
  1600. self.gesture.delegate = self;
  1601. [_seatCtrlView addGestureRecognizer:self.gesture];
  1602. [_seatCtrlView addSubview:self.seatActionView];
  1603. UIView *headView = [[UIView alloc] initWithFrame:CGRectMake(0, KPortraitHeight - 300 - iPhoneXSafeBottomMargin - 16, KPortraitWidth, 16)];
  1604. headView.backgroundColor = [UIColor whiteColor];
  1605. [_seatCtrlView addSubview:headView];
  1606. if (@available(iOS 11.0, *)) {
  1607. headView.layer.cornerRadius = 8;
  1608. headView.layer.maskedCorners = kCALayerMinXMinYCorner | kCALayerMaxXMinYCorner; // 左上圆角
  1609. }
  1610. else {
  1611. UIBezierPath * path = [UIBezierPath bezierPathWithRoundedRect:headView.bounds byRoundingCorners:UIRectCornerTopLeft | UIRectCornerTopRight cornerRadii:CGSizeMake(8, 8)];
  1612. CAShapeLayer *maskLayer = [[CAShapeLayer alloc] init];
  1613. maskLayer.frame = headView.bounds;
  1614. maskLayer.path = path.CGPath;
  1615. headView.layer.mask = maskLayer;
  1616. }
  1617. }
  1618. return _seatCtrlView;
  1619. }
  1620. - (void)hideSeatCtrlView {
  1621. if (_seatCtrlView) {
  1622. [_seatCtrlView removeFromSuperview];
  1623. }
  1624. }
  1625. - (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch {
  1626. if (gestureRecognizer == self.gesture) {
  1627. if ([touch.view isDescendantOfView:self.seatActionView]) {
  1628. return NO;
  1629. }
  1630. }
  1631. return YES;
  1632. }
  1633. - (LiveSeatActionView *)seatActionView {
  1634. if (!_seatActionView) {
  1635. _seatActionView = [[LiveSeatActionView alloc] initWithFrame:CGRectMake(0, kScreenHeight - 300 - iPhoneXSafeBottomMargin, kScreenWidth, 300 + iPhoneXSafeBottomMargin)];
  1636. MJWeakSelf;
  1637. [_seatActionView opreationCallback:^(LIVESECONTROL action, LiveSeatMember * _Nonnull member) {
  1638. [weakSelf opreationSeatApplyAction:action member:member];
  1639. }];
  1640. _seatActionView.isForbiddenApply = !self.enableSeat;
  1641. }
  1642. return _seatActionView;
  1643. }
  1644. - (void)opreationSeatApplyAction:(LIVESECONTROL)control member:(LiveSeatMember *)member {
  1645. switch (control) {
  1646. case LIVESECONTROL_ALLOW: // 允许连麦
  1647. {
  1648. [self sendMicStatusRequest:0];
  1649. }
  1650. break;
  1651. case LIVESECONTROL_FORBIDDEN: // 禁止连麦
  1652. {
  1653. [self sendMicStatusRequest:1];
  1654. }
  1655. break;
  1656. case LIVESECONTROL_APPROVE: // 上麦
  1657. {
  1658. if (member) {
  1659. // 判断连麦人数超过4人 无法点击
  1660. NSInteger count = [self queryConnectingCount];
  1661. if (count >= 4) {
  1662. [self MBPShow:@"最多支持4人上麦哦~"];
  1663. return;
  1664. }
  1665. KSLiveChatroomSeatResponse *responseMessage = [[KSLiveChatroomSeatResponse alloc] init];
  1666. responseMessage.type = SEATRESPONSE_TEACHERAPPROVE;
  1667. responseMessage.teacherId = self.createrId;
  1668. responseMessage.teacherName = self.createrName;
  1669. responseMessage.audienceId = member.userId;
  1670. responseMessage.audienceName = member.name;
  1671. MJWeakSelf;
  1672. [self sendMessage:responseMessage displayMessage:NO callback:^(BOOL success) {
  1673. [weakSelf refreshSeatArrayRemoveMember:NO member:member];
  1674. }];
  1675. }
  1676. }
  1677. break;
  1678. case LIVESECONTROL_DOWNSEAT: // 下麦
  1679. {
  1680. if (member) {
  1681. KSLiveChatroomSeatApply *kickSeatMessage = [[KSLiveChatroomSeatApply alloc] init];
  1682. kickSeatMessage.type = SEATHANDLE_KICKSEAT;
  1683. kickSeatMessage.teacherId = self.createrId;
  1684. kickSeatMessage.teacherName = self.createrName;
  1685. kickSeatMessage.audienceId = member.userId;
  1686. kickSeatMessage.audienceName = member.name;
  1687. MJWeakSelf;
  1688. [self sendMessage:kickSeatMessage displayMessage:NO callback:^(BOOL success) {
  1689. [weakSelf refreshSeatArrayRemoveMember:YES member:member];
  1690. }];
  1691. }
  1692. }
  1693. break;
  1694. case LIVESECONTROL_DOWNSEATALL:
  1695. {
  1696. MJWeakSelf;
  1697. self.alertView = [LiveRoomAlertView liveroomAlertWithTitle:@"确认后所有连麦中学员都将下麦" leftButtonTitle:@"取消" rightTitle:@"确认" inView:self.view cancel:^{
  1698. } confirm:^{
  1699. [weakSelf downSeatAll];
  1700. }];
  1701. }
  1702. break;
  1703. case LIVESECONTROL_REFUSEALL:
  1704. {
  1705. MJWeakSelf;
  1706. self.alertView = [LiveRoomAlertView liveroomAlertWithTitle:@"确认将正在申请连麦的学员清空?" leftButtonTitle:@"取消" rightTitle:@"确认" inView:self.view cancel:^{
  1707. } confirm:^{
  1708. [weakSelf refuseAllSeatApply];
  1709. }];
  1710. }
  1711. break;
  1712. default:
  1713. break;
  1714. }
  1715. }
  1716. // 是否允许连麦 0:是 1否
  1717. - (void)sendMicStatusRequest:(NSInteger)whetherMic {
  1718. [self showhud];
  1719. [KSNetworkingManager liveRoomSetMicApplyEnable:KS_GET roomUid:self.roomId whetherMic:whetherMic success:^(NSDictionary * _Nonnull dic) {
  1720. [self removehub];
  1721. if ([dic ks_integerValueForKey:@"code"] == 200 && [dic ks_boolValueForKey:@"status"]) {
  1722. if (whetherMic == 0) {
  1723. self.seatActionView.isForbiddenApply = NO;
  1724. [self enableSeatAction];
  1725. }
  1726. else {
  1727. self.seatActionView.isForbiddenApply = YES;
  1728. [self forceSeatAction];
  1729. }
  1730. }
  1731. else {
  1732. [self MBPShow:MESSAGEKEY];
  1733. }
  1734. } faliure:^(NSError * _Nonnull error) {
  1735. [self removehub];
  1736. }];
  1737. }
  1738. - (void)enableSeatAction {
  1739. RCChatroomSeatsControl *message = [[RCChatroomSeatsControl alloc] init];
  1740. message.userId = self.createrId;
  1741. message.userName = self.createrName;
  1742. message.seatBan = NO;
  1743. [self sendMessage:message displayMessage:NO callback:^(BOOL success) {
  1744. }];
  1745. }
  1746. // 禁止连麦
  1747. - (void)forceSeatAction {
  1748. RCChatroomSeatsControl *message = [[RCChatroomSeatsControl alloc] init];
  1749. message.userId = self.createrId;
  1750. message.userName = self.createrName;
  1751. message.seatBan = YES;
  1752. MJWeakSelf;
  1753. [self sendMessage:message displayMessage:NO callback:^(BOOL success) {
  1754. [weakSelf removeSeatMember:YES];
  1755. }];
  1756. }
  1757. // 全员下麦
  1758. - (void)downSeatAll {
  1759. KSDownSeatAllMessage *message = [[KSDownSeatAllMessage alloc] init];
  1760. MJWeakSelf;
  1761. [self sendMessage:message displayMessage:NO callback:^(BOOL success) {
  1762. [weakSelf removeSeatMember:NO];
  1763. }];
  1764. }
  1765. - (void)refuseAllSeatApply {
  1766. KSRejectAllSeatMessage *message = [[KSRejectAllSeatMessage alloc] init];
  1767. MJWeakSelf;
  1768. [self sendMessage:message displayMessage:NO callback:^(BOOL success) {
  1769. [weakSelf removeSeatMember:YES];
  1770. }];
  1771. }
  1772. - (void)removeSeatMember:(BOOL)isApply {
  1773. NSMutableArray *seatArray = [self.seatApplyArray mutableCopy];
  1774. if (isApply) {
  1775. NSMutableArray *array = [NSMutableArray array];
  1776. for (LiveSeatMember *member in seatArray) {
  1777. if (member.isConnected == YES) {
  1778. [array addObject:member];
  1779. }
  1780. }
  1781. self.seatApplyArray = [NSMutableArray arrayWithArray:array];
  1782. }
  1783. else {
  1784. NSMutableArray *array = [NSMutableArray array];
  1785. for (LiveSeatMember *member in seatArray) {
  1786. if (member.isConnected == NO) {
  1787. [array addObject:member];
  1788. }
  1789. }
  1790. self.seatApplyArray = [NSMutableArray arrayWithArray:array];
  1791. }
  1792. [self refreshSeatApplyView];
  1793. }
  1794. - (void)refreshSeatArrayRemoveMember:(BOOL)isRemove member:(LiveSeatMember *)member {
  1795. if (isRemove) {
  1796. [self.seatApplyArray removeObject:member];
  1797. }
  1798. else {
  1799. member.isConnected = YES;
  1800. if (![self judgeContainMember:member.userId]) {
  1801. [self.seatApplyArray addObject:member];
  1802. NSLog(@"hah--------");
  1803. }
  1804. }
  1805. [self refreshSeatApplyView];
  1806. }
  1807. - (NSMutableArray *)seatApplyArray {
  1808. if (!_seatApplyArray) {
  1809. _seatApplyArray = [NSMutableArray array];
  1810. }
  1811. return _seatApplyArray;
  1812. }
  1813. - (LiveMoreDisplayView *)moreView {
  1814. if (!_moreView) {
  1815. _moreView = [LiveMoreDisplayView shareInstance];
  1816. _moreView.frame = CGRectMake(0, 0, KPortraitWidth, KPortraitHeight);
  1817. MJWeakSelf;
  1818. [_moreView operationQuitAction:^(BOOL isCloseRoom) {
  1819. [weakSelf leaveRoom:isCloseRoom];
  1820. }];
  1821. }
  1822. return _moreView;
  1823. }
  1824. - (void)leaveRoom:(BOOL)closeRoom {
  1825. if (closeRoom) {
  1826. [self closeRoomAction];
  1827. }
  1828. else {
  1829. [self pauseAction];
  1830. }
  1831. }
  1832. - (LiveroomTimeManager *)timeManager {
  1833. if (!_timeManager) {
  1834. _timeManager = [[LiveroomTimeManager alloc] initWithDelegate:self];
  1835. }
  1836. return _timeManager;
  1837. }
  1838. - (NSInteger)getCloseTime {
  1839. return self.expiredCloseMinute;
  1840. }
  1841. - (void)dealloc {
  1842. NSLog(@"------- dealloc --------");
  1843. if (_timeManager) {
  1844. [_timeManager stopDurationTimer];
  1845. }
  1846. [[NSNotificationCenter defaultCenter] removeObserver:self];
  1847. if (_timer) {
  1848. dispatch_source_cancel(_timer);
  1849. _timer = nil;
  1850. }
  1851. }
  1852. - (dispatch_source_t)timer {
  1853. if (!_timer) {
  1854. _timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0,dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0));
  1855. uint64_t interval = (uint64_t)(10 * NSEC_PER_SEC);
  1856. dispatch_source_set_timer(_timer, DISPATCH_TIME_NOW, interval, 0);
  1857. MJWeakSelf;
  1858. dispatch_source_set_event_handler(_timer, ^{
  1859. dispatch_async(dispatch_get_main_queue(), ^{
  1860. [weakSelf syncLikeCount];
  1861. });
  1862. });
  1863. }
  1864. return _timer;
  1865. }
  1866. - (void)showAnimationView:(BOOL)isJoinRoom showMessag:(NSString *)message {
  1867. if (self.animationView && self.animationView.isShow) {
  1868. return;
  1869. }
  1870. else {
  1871. if (self.pageType == LIVEPAGE_PREVIEW) {
  1872. return;
  1873. }
  1874. ANIMATIONTYPE type = isJoinRoom ? ANIMATIONTYPE_JOIN : ANIMATIONTYPE_RUSH;
  1875. self.animationView = [[LiveAnimationView alloc] initWithTitle:message animationType:type];
  1876. [self.view addSubview:self.animationView];
  1877. [self.animationView mas_makeConstraints:^(MASConstraintMaker *make) {
  1878. make.left.right.mas_equalTo(self.view);
  1879. make.width.mas_equalTo(KPortraitWidth);
  1880. make.height.mas_equalTo(24.0f);
  1881. make.bottom.mas_equalTo(self.messageContentView.mas_top).offset(-6);
  1882. }];
  1883. [self.view bringSubviewToFront:self.animationView];
  1884. NSLog(@"------- start animation ");
  1885. MJWeakSelf;
  1886. [self.animationView startAnimationEndCallback:^{
  1887. NSLog(@"----- hide ");
  1888. weakSelf.animationView.isShow = YES;
  1889. weakSelf.animationView = nil;
  1890. }];
  1891. }
  1892. }
  1893. #pragma mark ---- 同步点赞数据
  1894. - (void)syncLikeCount {
  1895. if (self.isOtherLogin) {
  1896. return;
  1897. }
  1898. [KSNetworkingManager syncLikeRequest:KS_GET likeNum:self.likeCount roomUid:self.roomId success:^(NSDictionary * _Nonnull dic) {
  1899. if ([dic ks_integerValueForKey:@"code"] == 200 && [dic ks_boolValueForKey:@"status"]) {
  1900. [self notiferLikeStatusToAudience];
  1901. }
  1902. } faliure:^(NSError * _Nonnull error) {
  1903. }];
  1904. }
  1905. - (void)notiferLikeStatusToAudience {
  1906. RCChatroomLikeCount *likeCountMsg = [[RCChatroomLikeCount alloc] init];
  1907. likeCountMsg.count = self.likeCount;
  1908. [self sendMessage:likeCountMsg displayMessage:NO callback:^(BOOL success) {
  1909. }];
  1910. }
  1911. /*
  1912. #pragma mark - Navigation
  1913. // In a storyboard-based application, you will often want to do a little preparation before navigation
  1914. - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
  1915. // Get the new view controller using [segue destinationViewController].
  1916. // Pass the selected object to the new view controller.
  1917. }
  1918. */
  1919. @end