|
@@ -1,2201 +0,0 @@
|
|
|
-//
|
|
|
-// LiveRoomViewController.m
|
|
|
-// KulexiuForTeacher
|
|
|
-//
|
|
|
-// Created by 王智 on 2022/6/21.
|
|
|
-//
|
|
|
-
|
|
|
-#import "LiveRoomViewController.h"
|
|
|
-#import "LivePreviewBodyView.h"
|
|
|
-#import <RongRTCLib/RongRTCLib.h>
|
|
|
-#import <RongIMKit/RongIMKit.h>
|
|
|
-#import <RongFaceBeautifier/RongFaceBeautifier.h>
|
|
|
-#import "KSBeautySettingView.h"
|
|
|
-#import "KSEnterLiveroomManager.h"
|
|
|
-#import "LiveroomTimeManager.h"
|
|
|
-
|
|
|
-#import "UserInfoManager.h"
|
|
|
-#import "KSChatInputBarControl.h"
|
|
|
-#import "LiveRoomHeadView.h"
|
|
|
-#import "LiveRoomBottomView.h"
|
|
|
-#import "SeatContentView.h"
|
|
|
-#import "SeatTipsView.h"
|
|
|
-#import "KSLiveStreamVideo.h"
|
|
|
-#import "KSRCMessageModel.h"
|
|
|
-#import "KSChatroomMessageCenter.h"
|
|
|
-#import "KSChatroomTextCell.h"
|
|
|
-#import "LiveRoomAlertView.h"
|
|
|
-#import "LiveMoreDisplayView.h"
|
|
|
-#import "LiveAnimationView.h"
|
|
|
-#import "KSShareChooseViewController.h"
|
|
|
-#import "KSChatLiveMessage.h"
|
|
|
-
|
|
|
-#import "LiveSeatActionView.h"
|
|
|
-//#import <ImSDK_Plus/V2TIMManager.h>
|
|
|
-
|
|
|
-typedef NS_ENUM(NSInteger, LIVEPAGE) {
|
|
|
- LIVEPAGE_PREVIEW,
|
|
|
- LIVEPAGE_LIVE,
|
|
|
-};
|
|
|
-
|
|
|
-@interface LiveRoomViewController ()<RCRTCEngineEventDelegate,RCRTCRoomEventDelegate,RCRTCStatusReportDelegate,UIGestureRecognizerDelegate,KSChatInputBarControlDelegate,UITableViewDataSource,UITableViewDelegate,LiveroomTimeManagerDelegate>
|
|
|
-
|
|
|
-@property (nonatomic, strong) LiveroomTimeManager *timeManager;
|
|
|
-
|
|
|
-@property (nonatomic, assign) LIVEPAGE pageType;
|
|
|
-
|
|
|
-@property (nonatomic, assign) BOOL isPauseLive; // 是否暂停直播
|
|
|
-
|
|
|
-@property (nonatomic, assign) BOOL isOtherLogin; // 是否被顶掉
|
|
|
-
|
|
|
-@property (nonatomic, strong) LivePreviewBodyView *previewPageView;
|
|
|
-
|
|
|
-@property (nonatomic, strong) RCRTCVideoView *preVideoView;
|
|
|
-
|
|
|
-@property (nonatomic, strong) KSBeautySettingView *settingView;
|
|
|
-
|
|
|
-@property (nonatomic, assign) BOOL isBeautyOn;
|
|
|
-
|
|
|
-@property (nonatomic, assign) int filterLevel;
|
|
|
-
|
|
|
-#pragma mark ------- 直播房间信息
|
|
|
-/*!
|
|
|
- 身份状态 老师/观众
|
|
|
- */
|
|
|
-@property (nonatomic, assign) RCRTCLiveRoleType liveRoleType;
|
|
|
-/// 老师id
|
|
|
-@property (nonatomic, strong) NSString *createrId;
|
|
|
-/// 老师名称
|
|
|
-@property (nonatomic, strong) NSString *createrName;
|
|
|
-/// 老师头像
|
|
|
-@property (nonatomic, strong) NSString *createrAvatal;
|
|
|
-
|
|
|
-// 是否禁止连麦
|
|
|
-@property (nonatomic, assign) BOOL enableSeat;
|
|
|
-// 是否禁止聊天
|
|
|
-@property (nonatomic, assign) BOOL enableChat;
|
|
|
-// 是否允许点赞
|
|
|
-@property (nonatomic, assign) BOOL enableLike;
|
|
|
-
|
|
|
-@property (nonatomic, assign) NSInteger likeCount;
|
|
|
-/// 房间人数
|
|
|
-@property (nonatomic, assign) NSInteger totalCount;
|
|
|
-
|
|
|
-#pragma mark ---- Live page
|
|
|
-
|
|
|
-@property (nonatomic, strong) UIView *livePageView;
|
|
|
-
|
|
|
-@property (nonatomic, strong) RCRTCRoom *room;
|
|
|
-
|
|
|
-@property (nonatomic, assign) BOOL isImConnected;
|
|
|
-
|
|
|
-@property (nonatomic, assign) BOOL hasJoinRoomSuccess;
|
|
|
-
|
|
|
-@property (nonatomic, strong) KSLiveStreamVideo *localVideo;
|
|
|
-
|
|
|
-@property (nonatomic, strong) UIView *liveVideoView;
|
|
|
-
|
|
|
-@property (nonatomic, strong) LiveRoomHeadView *headView;
|
|
|
-
|
|
|
-@property (nonatomic, copy) LiveRoomBottomView *bottomView;
|
|
|
-
|
|
|
-/// 连麦的视图
|
|
|
-@property (nonatomic, strong) SeatContentView *seatContainer;
|
|
|
-// 聊天UI
|
|
|
-/*!
|
|
|
- 消息列表CollectionView和输入框都在这个view里
|
|
|
- */
|
|
|
-@property(nonatomic, strong) UIView *messageContentView;
|
|
|
-
|
|
|
-/*!
|
|
|
- 会话页面的TableView
|
|
|
- */
|
|
|
-@property (nonatomic, strong) UITableView *conversationMessageTableView;
|
|
|
-
|
|
|
-/*!
|
|
|
- 聊天内容的消息Cell数据模型的数据源
|
|
|
-
|
|
|
- @discussion 数据源中存放的元素为消息Cell的数据模型,即RCDLiveMessageModel对象。
|
|
|
- */
|
|
|
-@property(nonatomic, strong) NSMutableArray<KSRCMessageModel *> *conversationDataRepository;
|
|
|
-/**
|
|
|
- 输入工具栏
|
|
|
- */
|
|
|
-@property(nonatomic,strong) KSChatInputBarControl *inputBar;
|
|
|
-/**
|
|
|
- * 是否需要滚动到底部
|
|
|
- */
|
|
|
-@property(nonatomic, assign) BOOL isNeedScrollToButtom;
|
|
|
-
|
|
|
-@property (nonatomic, strong) UIView *seatCtrlView;
|
|
|
-
|
|
|
-@property (nonatomic, strong) LiveSeatActionView *seatActionView;
|
|
|
-
|
|
|
-@property (nonatomic, strong) NSMutableArray *seatApplyArray; // 申请连麦数组
|
|
|
-// 远端连麦用户
|
|
|
-@property (nonatomic, strong) NSMutableArray *remoteMemberArray;
|
|
|
-
|
|
|
-/// 连麦申请统计数据
|
|
|
-@property (nonatomic, strong) SeatTipsView *seatApplyTips;
|
|
|
-
|
|
|
-/// 提示窗
|
|
|
-@property (nonatomic, strong) LiveRoomAlertView *alertView;
|
|
|
-
|
|
|
-// 定时器
|
|
|
-@property (nonatomic, strong) dispatch_source_t timer;
|
|
|
-
|
|
|
-@property (nonatomic, strong) LiveMoreDisplayView *moreView;
|
|
|
-
|
|
|
-@property (nonatomic) LiveAnimationView *animationView;
|
|
|
-
|
|
|
-/// 直播课结束时间
|
|
|
-@property (nonatomic, strong) NSString *liveEndTime;
|
|
|
-
|
|
|
-/// 直播间关闭延迟时间
|
|
|
-@property (nonatomic, assign) NSInteger expiredCloseMinute;
|
|
|
-
|
|
|
-@property (nonatomic, copy) LiveRoomBackAction callback;
|
|
|
-
|
|
|
-@property (nonatomic, strong) UITapGestureRecognizer *gesture;
|
|
|
-
|
|
|
-@property (nonatomic, assign) BOOL needPublishStream;
|
|
|
-
|
|
|
-@property (nonatomic, assign) BOOL micEnable;
|
|
|
-
|
|
|
-@end
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-@implementation LiveRoomViewController
|
|
|
-
|
|
|
-- (void)backRefreshCallback:(LiveRoomBackAction)callback {
|
|
|
- if (callback) {
|
|
|
- self.callback = callback;
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-- (void)viewDidLoad {
|
|
|
- [super viewDidLoad];
|
|
|
- // Do any additional setup after loading the view.
|
|
|
- self.ks_prefersNavigationBarHidden = YES;
|
|
|
- self.isOtherLogin = NO;
|
|
|
- [self registerOtherLoginNotice];
|
|
|
- [self configUI];
|
|
|
- [self configEngine];
|
|
|
- self.pageType = LIVEPAGE_PREVIEW;
|
|
|
- [self countUMEvent];
|
|
|
-}
|
|
|
-
|
|
|
-- (void)countUMEvent {
|
|
|
- [USER_MANAGER sendUMEvent:@"klx_live"];
|
|
|
-}
|
|
|
-
|
|
|
-- (void)registerOtherLoginNotice {
|
|
|
- [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(liveroomLogOut) name:@"liveroomLogout" object:nil];
|
|
|
- [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(liveroomQuit) name:@"liveroomQuit" object:nil];
|
|
|
-}
|
|
|
-
|
|
|
-- (void)viewWillAppear:(BOOL)animated {
|
|
|
- [super viewWillAppear:animated];
|
|
|
- [UIApplication sharedApplication].idleTimerDisabled = YES;
|
|
|
- [IQKeyboardManager sharedManager].enableAutoToolbar = NO;
|
|
|
- [IQKeyboardManager sharedManager].enable = NO;
|
|
|
- [UIApplication sharedApplication].statusBarStyle = UIStatusBarStyleLightContent;
|
|
|
-}
|
|
|
-
|
|
|
-- (void)viewWillDisappear:(BOOL)animated {
|
|
|
- [super viewWillDisappear:animated];
|
|
|
- [UIApplication sharedApplication].idleTimerDisabled = NO;
|
|
|
- [IQKeyboardManager sharedManager].enableAutoToolbar = YES;
|
|
|
- [IQKeyboardManager sharedManager].enable = YES;
|
|
|
- if (@available(iOS 13.0, *)) {
|
|
|
- [UIApplication sharedApplication].statusBarStyle = UIStatusBarStyleDarkContent;
|
|
|
- } else {
|
|
|
- // Fallback on earlier versions
|
|
|
- [UIApplication sharedApplication].statusBarStyle = UIStatusBarStyleDefault;
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-- (void)configUI {
|
|
|
- self.previewPageView = [LivePreviewBodyView shareInstance];
|
|
|
- [self.view addSubview:self.previewPageView];
|
|
|
- [self.previewPageView mas_makeConstraints:^(MASConstraintMaker *make) {
|
|
|
- make.left.right.bottom.top.mas_equalTo(self.view);
|
|
|
- }];
|
|
|
- MJWeakSelf;
|
|
|
- [self.previewPageView previewOperationCallback:^(PREVIEWLIVEACTION action) {
|
|
|
- [weakSelf previewOperationAction:action];
|
|
|
- }];
|
|
|
- [[RCRTCBeautyEngine sharedInstance] reset];
|
|
|
-}
|
|
|
-
|
|
|
-- (void)configEngine {
|
|
|
- if (!self.preVideoView) {
|
|
|
- self.preVideoView = [[RCRTCVideoView alloc] init];
|
|
|
- self.preVideoView.fillMode = RCRTCVideoFillModeAspectFill;
|
|
|
-
|
|
|
- self.preVideoView.frameAnimated = NO;
|
|
|
- [self.previewPageView.videoView addSubview:self.preVideoView];
|
|
|
- [self.preVideoView mas_makeConstraints:^(MASConstraintMaker *make) {
|
|
|
- make.left.top.bottom.right.mas_equalTo(self.previewPageView.videoView);
|
|
|
- }];
|
|
|
- }
|
|
|
- [[RCRTCEngine sharedInstance].defaultVideoStream setVideoView:self.preVideoView];
|
|
|
- RCRTCVideoStreamConfig *videoConfig = [RCRTCEngine sharedInstance].defaultVideoStream.videoConfig;
|
|
|
- videoConfig.videoSizePreset = RCRTCVideoSizePreset1280x720;
|
|
|
- videoConfig.maxBitrate = 2200;
|
|
|
- videoConfig.minBitrate = 200;
|
|
|
- [[RCRTCEngine sharedInstance].defaultVideoStream setVideoConfig:videoConfig];
|
|
|
- [[RCRTCEngine sharedInstance].defaultVideoStream startCapture];
|
|
|
- self.filterLevel = 50;
|
|
|
-}
|
|
|
-
|
|
|
-- (void)previewOperationAction:(PREVIEWLIVEACTION)action {
|
|
|
- switch (action) {
|
|
|
- case PREVIEWLIVEACTION_BACK: // 返回
|
|
|
- {
|
|
|
- if (self.isPauseLive) { // 退出RTC房间
|
|
|
- [self quitRoomBackPreView:NO];
|
|
|
- }
|
|
|
- else {
|
|
|
- self.room = nil;
|
|
|
- self.preVideoView = nil;
|
|
|
- [[RCRTCEngine sharedInstance].defaultVideoStream stopCapture];
|
|
|
- if (self.callback) {
|
|
|
- self.callback();
|
|
|
- }
|
|
|
- [self.navigationController dismissViewControllerAnimated:YES completion:nil];
|
|
|
- }
|
|
|
- }
|
|
|
- break;
|
|
|
- case PREVIEWLIVEACTION_SWITCH: // 切换
|
|
|
- {
|
|
|
- [self switchCamera];
|
|
|
- }
|
|
|
- break;
|
|
|
- case PREVIEWLIVEACTION_BEAUTY: // 美颜
|
|
|
- {
|
|
|
- [self displayBeautyView];
|
|
|
- }
|
|
|
- break;
|
|
|
- case PREVIEWLIVEACTION_SHARE: // 分享
|
|
|
- {
|
|
|
- [self shareLiveRoomMessage];
|
|
|
- }
|
|
|
- break;
|
|
|
- case PREVIEWLIVEACTION_OPEN: // 进入直播间
|
|
|
- {
|
|
|
- [self showLiveView];
|
|
|
- }
|
|
|
- break;
|
|
|
- default:
|
|
|
- break;
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-- (void)shareLiveRoomMessage {
|
|
|
- // 选择群组分享
|
|
|
-
|
|
|
- NSMutableDictionary *parm = [NSMutableDictionary dictionary];
|
|
|
- [parm setValue:@"TC_CHATSHARE_LIVE" forKey:@"businessID"];
|
|
|
- [parm setValue:@"TXLiveShareCell" forKey:@"TMessageCell_Name"];
|
|
|
- [parm setValue:@"TXLiveShareMessage" forKey:@"TMessageCell_Name"];
|
|
|
-
|
|
|
- NSString *teacherName = UserDefaultObjectForKey(NicknameKey);
|
|
|
- if ([NSString isEmptyString:teacherName]) {
|
|
|
- teacherName = [NSString stringWithFormat:@"游客%@",UserDefaultObjectForKey(UIDKey)];
|
|
|
- }
|
|
|
- [parm setValue:self.roomId forKey:@"roomUID"];
|
|
|
- [parm setValue:teacherName forKey:@"teacherName"];
|
|
|
- [parm setValue:UserDefaultObjectForKey(AvatarUrlKey) forKey:@"teacherAvatar"];
|
|
|
- [parm setValue:self.liveContent forKey:@"liveContent"];
|
|
|
-
|
|
|
- NSData *data = [NSJSONSerialization dataWithJSONObject:parm options:0 error:nil];
|
|
|
-
|
|
|
-
|
|
|
- KSShareChooseViewController *chooseCtrl = [[KSShareChooseViewController alloc] init];
|
|
|
- chooseCtrl.msgData = data;
|
|
|
- [self.navigationController pushViewController:chooseCtrl animated:YES];
|
|
|
-}
|
|
|
-
|
|
|
-- (void)displayBeautyView {
|
|
|
- [self displayBottomView:YES];
|
|
|
- if (_settingView == nil) {
|
|
|
-
|
|
|
- RCRTCBeautyOption *option = [[RCRTCBeautyEngine sharedInstance] getCurrentBeautyOption];
|
|
|
- RCRTCBeautyFilter filter = [[RCRTCBeautyEngine sharedInstance] getCurrentBeautyFilter];
|
|
|
- FILTER_TYPE type = [self getFilterType:filter];
|
|
|
- MJWeakSelf;
|
|
|
- [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) {
|
|
|
- [weakSelf configSettingBeauty:YES white:white smoothLevel:smoothLevel ruddyLevel:ruddyLevel brightLevel:brightLevel filter:[weakSelf getRongBeautyWithType:type] filterLevel:filterLevel];
|
|
|
- }];
|
|
|
- }
|
|
|
-
|
|
|
- [self.view addSubview:self.settingView];
|
|
|
- [self.settingView mas_makeConstraints:^(MASConstraintMaker *make) {
|
|
|
- make.left.right.top.bottom.mas_equalTo(self.view);
|
|
|
- }];
|
|
|
-}
|
|
|
-
|
|
|
-- (FILTER_TYPE)getFilterType:(RCRTCBeautyFilter)filter {
|
|
|
- switch (filter) {
|
|
|
- case RCRTCBeautyFilterNone:
|
|
|
- return FILTER_TYPE_NONE;
|
|
|
- case RCRTCBeautyFilterFresh:
|
|
|
- return FILTER_TYPE_QINGXIN;
|
|
|
- case RCRTCBeautyFilterEsthetic:
|
|
|
- return FILTER_TYPE_WEIMEI;
|
|
|
- case RCRTCBeautyFilterRomantic:
|
|
|
- return FILTER_TYPE_LANGMAN;
|
|
|
- default:
|
|
|
- return FILTER_TYPE_NONE;
|
|
|
- break;
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-- (RCRTCBeautyFilter)getRongBeautyWithType:(FILTER_TYPE)type {
|
|
|
- switch (type) {
|
|
|
- case FILTER_TYPE_NONE:
|
|
|
- return RCRTCBeautyFilterNone;
|
|
|
- case FILTER_TYPE_QINGXIN:
|
|
|
- return RCRTCBeautyFilterFresh;
|
|
|
- case FILTER_TYPE_WEIMEI:
|
|
|
- return RCRTCBeautyFilterEsthetic;
|
|
|
- case FILTER_TYPE_LANGMAN:
|
|
|
- return RCRTCBeautyFilterRomantic;
|
|
|
- default:
|
|
|
- return RCRTCBeautyFilterNone;
|
|
|
- break;
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-- (void)configSettingBeauty:(BOOL)isOn white:(NSInteger)whitenessLevel smoothLevel:(NSInteger)smoothLevel ruddyLevel:(NSInteger)ruddyLevel brightLevel:(NSInteger)brightLevel filter:(RCRTCBeautyFilter)filter filterLevel:(int)filterLevel {
|
|
|
- self.isBeautyOn = isOn;
|
|
|
- if (isOn) {
|
|
|
- // 获取当前美颜参数
|
|
|
- RCRTCBeautyOption *option = [[RCRTCBeautyEngine sharedInstance] getCurrentBeautyOption];
|
|
|
- // 修改参数
|
|
|
- option.whitenessLevel = whitenessLevel;
|
|
|
- option.smoothLevel = smoothLevel;
|
|
|
- option.ruddyLevel = ruddyLevel;
|
|
|
- option.brightLevel = brightLevel;
|
|
|
- // 设置美颜
|
|
|
- [[RCRTCBeautyEngine sharedInstance] setBeautyOption:isOn option:option];
|
|
|
- // 设置滤镜
|
|
|
- [[RCRTCBeautyEngine sharedInstance] setBeautyFilter:filter];
|
|
|
- // 设置滤镜强度
|
|
|
- [[RCRTCBeautyEngine sharedInstance] setFilterIntensity:filterLevel];
|
|
|
- }
|
|
|
- else {
|
|
|
- [[RCRTCBeautyEngine sharedInstance] reset];
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-- (void)showLiveView {
|
|
|
-
|
|
|
- if (self.isPauseLive) { // 直接切换页面
|
|
|
-// self.micEnable = self.micEnable;
|
|
|
- self.pageType = LIVEPAGE_LIVE;
|
|
|
- [self.view addSubview:self.livePageView];
|
|
|
- [self.livePageView mas_makeConstraints:^(MASConstraintMaker *make) {
|
|
|
- make.left.right.top.bottom.mas_equalTo(self.view);
|
|
|
- }];
|
|
|
- // 开启推流
|
|
|
- [self startPublishStream];
|
|
|
- }
|
|
|
- else {
|
|
|
- [LOADING_MANAGER showHUD];
|
|
|
- MJWeakSelf;
|
|
|
- [KSEnterLiveroomManager queryLiveroomConfig:self.roomId callback:^(NSDictionary * _Nullable parm) {
|
|
|
- [LOADING_MANAGER removeHUD];
|
|
|
- if (parm != nil) {
|
|
|
- [weakSelf setupLiveroomConfig:parm];
|
|
|
- [weakSelf createLivePageViewDisplay];
|
|
|
- }
|
|
|
- }];
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-- (void)startPublishStream {
|
|
|
- self.pageType = LIVEPAGE_LIVE;
|
|
|
- self.isPauseLive = NO;
|
|
|
- [self publishLocalStream];
|
|
|
-}
|
|
|
-
|
|
|
-- (void)setupLiveroomConfig:(NSDictionary *)source {
|
|
|
- NSLog(@"room config----- %@",source);
|
|
|
- self.liveRoleType = RCRTCLiveRoleTypeBroadcaster;
|
|
|
- self.createrId = [source ks_stringValueForKey:@"speakerId"];
|
|
|
- self.createrName = [source ks_stringValueForKey:@"speakerName"];
|
|
|
- self.createrAvatal = [source ks_stringValueForKey:@"speakerPic"];
|
|
|
- self.likeCount = [source ks_integerValueForKey:@"likeNum"]; // 点赞数
|
|
|
- NSInteger lookCount = [source ks_integerValueForKey:@"lookNum"];
|
|
|
- self.totalCount = lookCount; // 观看人数
|
|
|
-
|
|
|
- self.enableSeat = ![source ks_boolValueForKey:@"whether_mic"];
|
|
|
-
|
|
|
- BOOL isTemp = [[source ks_stringValueForKey:@"roomType"] isEqualToString:@"TEMP"];
|
|
|
- self.isTempRoom = isTemp;
|
|
|
- if (isTemp == NO) {
|
|
|
- self.liveEndTime = [source ks_stringValueForKey:@"liveEndTime"];
|
|
|
- self.expiredCloseMinute = [source ks_integerValueForKey:@"expiredCloseMinute"];
|
|
|
- }
|
|
|
- else {
|
|
|
- self.liveEndTime = [source ks_stringValueForKey:@"liveEndTime"];
|
|
|
- self.expiredCloseMinute = 0;
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-- (void)createLivePageViewDisplay {
|
|
|
- self.micEnable = YES;
|
|
|
- self.pageType = LIVEPAGE_LIVE;
|
|
|
- self.isImConnected = [USER_MANAGER checkIMConnected];
|
|
|
- [self registerNotification];
|
|
|
- [self setupUI];
|
|
|
- [self configIMConnect];
|
|
|
- [self startTimer];
|
|
|
-}
|
|
|
-
|
|
|
-#pragma mark --- settingView
|
|
|
-- (KSBeautySettingView *)settingView {
|
|
|
- if (!_settingView) {
|
|
|
- _settingView = [KSBeautySettingView shareInstance];
|
|
|
- MJWeakSelf;
|
|
|
- [_settingView hiddenViewCallback:^{
|
|
|
- [weakSelf displayBottomView:NO];
|
|
|
- }];
|
|
|
-
|
|
|
- }
|
|
|
- return _settingView;
|
|
|
-}
|
|
|
-
|
|
|
-- (void)displayBottomView:(BOOL)isHidden {
|
|
|
- if (isHidden) {
|
|
|
- self.previewPageView.functionView.hidden = YES;
|
|
|
- }
|
|
|
- else {
|
|
|
- self.previewPageView.functionView.hidden = NO;
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
-#pragma mark ------- Live page
|
|
|
-- (void)startTimer {
|
|
|
- if (self.timer) {
|
|
|
- dispatch_resume(self.timer);
|
|
|
- }
|
|
|
-}
|
|
|
-- (void)registerNotification {
|
|
|
-
|
|
|
- [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(IMConnetedCallback) name:@"RongIMConnected" object:nil];
|
|
|
- [KSChatroomMessageCenter registerMessageTypes];
|
|
|
- [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didReceiveMessageNotification:) name:OnReceiveChatroomMessageNotification object:nil];
|
|
|
-
|
|
|
- [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(appEnterBackground) name:@"appEnterBackground" object:nil];
|
|
|
- [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(appBecomeActive) name:@"appBecomeActive" object:nil];
|
|
|
- [self configTimerManager];
|
|
|
-}
|
|
|
-
|
|
|
-- (void)configTimerManager {
|
|
|
-
|
|
|
- self.timeManager.endClassTime = self.liveEndTime;
|
|
|
- self.timeManager.autoCloseNetworkRoomTime = [self getCloseTime];
|
|
|
- self.timeManager.isTempRoom = self.isTempRoom;
|
|
|
-}
|
|
|
-
|
|
|
-#pragma mark ------ enter back ground
|
|
|
-- (void)appEnterBackground {
|
|
|
- self.isEnterBackground = YES;
|
|
|
- if (self.isPauseLive == NO) { // 暂停推流
|
|
|
- [self pauseLiveActionBack:NO];
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-- (void)appBecomeActive {
|
|
|
- if (self.isEnterBackground && self.pageType == LIVEPAGE_LIVE && self.isOtherLogin == NO) {
|
|
|
- if ([USER_MANAGER checkIMConnected]) {
|
|
|
- // 开启推流
|
|
|
- [self startPublishStream];
|
|
|
- }
|
|
|
- else {
|
|
|
- self.needPublishStream = YES;
|
|
|
- }
|
|
|
-
|
|
|
- }
|
|
|
- self.isEnterBackground = NO;
|
|
|
-}
|
|
|
-
|
|
|
-- (void)setupUI {
|
|
|
- CGSize size = self.view.bounds.size;
|
|
|
- [self.view addSubview:self.livePageView];
|
|
|
- [self.livePageView mas_makeConstraints:^(MASConstraintMaker *make) {
|
|
|
- make.left.right.top.bottom.mas_equalTo(self.view);
|
|
|
- }];
|
|
|
-
|
|
|
- [self.livePageView addSubview:self.liveVideoView];
|
|
|
- [self.liveVideoView mas_makeConstraints:^(MASConstraintMaker *make) {
|
|
|
- make.left.top.bottom.right.mas_equalTo(self.livePageView);
|
|
|
- }];
|
|
|
-
|
|
|
- [self.livePageView addSubview:self.headView];
|
|
|
-
|
|
|
- [self.headView mas_makeConstraints:^(MASConstraintMaker *make) {
|
|
|
- make.left.right.mas_equalTo(self.livePageView);
|
|
|
- make.height.mas_equalTo(90);
|
|
|
- if (@available(iOS 11.0, *)) {
|
|
|
- make.top.mas_equalTo(self.livePageView.mas_safeAreaLayoutGuideTop).offset(10);
|
|
|
- } else {
|
|
|
- // Fallback on earlier versions
|
|
|
- make.top.mas_equalTo(self.livePageView.mas_top).offset(10);
|
|
|
- }
|
|
|
- }];
|
|
|
- [self.livePageView addSubview:self.messageContentView];
|
|
|
- [self.livePageView addSubview:self.bottomView];
|
|
|
-
|
|
|
- self.headView.boardcastName.text = [NSString returnNoNullStringWithString:self.createrName];
|
|
|
- if (![NSString isEmptyString:self.createrAvatal]) {
|
|
|
- [self.headView.boardcastAvatal sd_setImageWithURL:[NSURL URLWithString:[self.createrAvatal getUrlEndcodeString]] placeholderImage:[UIImage imageNamed:@"teacher_logo"]];
|
|
|
- }
|
|
|
- [self countLikeMessageCount];
|
|
|
-
|
|
|
- [self.headView mas_makeConstraints:^(MASConstraintMaker *make) {
|
|
|
- make.left.right.mas_equalTo(self.livePageView);
|
|
|
- make.height.mas_equalTo(90);
|
|
|
- if (@available(iOS 11.0, *)) {
|
|
|
- make.top.mas_equalTo(self.livePageView.mas_safeAreaLayoutGuideTop).offset(10);
|
|
|
- } else {
|
|
|
- // Fallback on earlier versions
|
|
|
- make.top.mas_equalTo(self.livePageView.mas_top).offset(10);
|
|
|
- }
|
|
|
- }];
|
|
|
- [self.livePageView addSubview:self.messageContentView];
|
|
|
- [self.livePageView addSubview:self.bottomView];
|
|
|
-
|
|
|
- [self.bottomView mas_makeConstraints:^(MASConstraintMaker *make) {
|
|
|
- make.left.right.mas_equalTo(self.livePageView);
|
|
|
- if (@available(iOS 11.0, *)) {
|
|
|
- make.bottom.mas_equalTo(self.livePageView.mas_safeAreaLayoutGuideBottom).offset(-5);
|
|
|
- } else {
|
|
|
- // Fallback on earlier versions
|
|
|
- make.bottom.mas_equalTo(self.livePageView.mas_bottom).offset(-5);
|
|
|
- }
|
|
|
- make.height.mas_equalTo(44);
|
|
|
- }];
|
|
|
-
|
|
|
- [self.messageContentView mas_makeConstraints:^(MASConstraintMaker *make) {
|
|
|
- make.left.mas_equalTo(self.livePageView.mas_left);
|
|
|
- make.right.mas_equalTo(self.livePageView.mas_right);
|
|
|
- make.bottom.mas_equalTo(self.bottomView.mas_top).offset(-5);
|
|
|
- make.height.mas_equalTo(180);
|
|
|
- }];
|
|
|
- [self.livePageView addSubview:self.inputBar];
|
|
|
- [_inputBar setBackgroundColor: [UIColor whiteColor]];
|
|
|
-
|
|
|
- [_inputBar setFrame:CGRectMake(0, kScreenHeight, size.width , 50)];
|
|
|
- [_inputBar setHidden:YES];
|
|
|
-
|
|
|
- [self.messageContentView addSubview:self.conversationMessageTableView];
|
|
|
- [self.conversationMessageTableView mas_makeConstraints:^(MASConstraintMaker *make) {
|
|
|
- make.left.top.mas_equalTo(self.messageContentView);
|
|
|
- make.width.mas_equalTo(KPortraitWidth);
|
|
|
- make.bottom.mas_equalTo(self.messageContentView.mas_bottom);
|
|
|
- }];
|
|
|
-
|
|
|
- [self.livePageView addSubview:self.seatApplyTips];
|
|
|
- [self.seatApplyTips hideView];
|
|
|
- [self.seatApplyTips mas_makeConstraints:^(MASConstraintMaker *make) {
|
|
|
- make.bottom.mas_equalTo(self.bottomView.mas_top).offset(2);
|
|
|
- make.height.mas_equalTo(20);
|
|
|
- make.left.mas_equalTo(self.bottomView.mas_right).offset(-116);
|
|
|
- }];
|
|
|
-
|
|
|
- UITapGestureRecognizer *resetBottomTapGesture =[[UITapGestureRecognizer alloc]
|
|
|
- initWithTarget:self
|
|
|
- action:@selector(resetBottomGesture:)];
|
|
|
- resetBottomTapGesture.delegate = self;
|
|
|
- [self.livePageView addGestureRecognizer:resetBottomTapGesture];
|
|
|
-}
|
|
|
-
|
|
|
-- (void)joinChatRoom {
|
|
|
-
|
|
|
- [[RCIMClient sharedRCIMClient] joinChatRoom:self.roomId messageCount:-1 success:^{
|
|
|
- dispatch_async(dispatch_get_main_queue(), ^{
|
|
|
- [self addConstMessage];
|
|
|
- self.hasJoinRoomSuccess = YES;
|
|
|
- });
|
|
|
- } error:^(RCErrorCode status) {
|
|
|
- if (status == RC_CHATROOM_NOT_EXIST || status == KICKED_FROM_CHATROOM || status == RC_PARAMETER_INVALID_CHATROOM) {
|
|
|
- dispatch_async(dispatch_get_main_queue(), ^{
|
|
|
- [LOADING_MANAGER MBShowAUTOHidingInWindow:@"加入聊天室失败"];
|
|
|
- });
|
|
|
- }
|
|
|
- }];
|
|
|
-}
|
|
|
-
|
|
|
-- (void)configIMConnect {
|
|
|
- if (self.isImConnected == YES) {
|
|
|
- [self connectionService];
|
|
|
- }
|
|
|
- else {
|
|
|
- MJWeakSelf;
|
|
|
- [USER_MANAGER connectionIMCallback:^(BOOL isSuccess) {
|
|
|
- dispatch_main_async_safe(^{
|
|
|
- [weakSelf connectionService];
|
|
|
- });
|
|
|
- }];
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-- (void)IMConnetedCallback {
|
|
|
-
|
|
|
- dispatch_main_async_safe(^{
|
|
|
- // IM 连接成功回调
|
|
|
- if (self.hasJoinRoomSuccess) { // 如果已经发送了进入消息
|
|
|
- // 查询是否直播间开启
|
|
|
- [KSNetworkingManager speakerCheckRoomInfoRequest:KS_GET roomUid:self.roomId success:^(NSDictionary * _Nonnull dic) {
|
|
|
- if ([dic ks_integerValueForKey:@"code"] == 200 && [dic ks_boolValueForKey:@"status"]) {
|
|
|
- // 回调信息
|
|
|
- MJWeakSelf;
|
|
|
- [self notiferJoinSuccessToServiceCallback:^{
|
|
|
- [LOADING_MANAGER MBShowAUTOHidingInWindow:@"IM连接成功"];
|
|
|
- [weakSelf joinChatRoomAndLiveRoom];
|
|
|
- }];
|
|
|
- }
|
|
|
- else {
|
|
|
- [LOADING_MANAGER MBShowAUTOHidingInWindow:MESSAGEKEY];
|
|
|
- [self quitRoomBackPreView:NO];
|
|
|
- }
|
|
|
- } faliure:^(NSError * _Nonnull error) {
|
|
|
-
|
|
|
- }];
|
|
|
- }
|
|
|
- if (self.needPublishStream) {
|
|
|
- [self startPublishStream];
|
|
|
- }
|
|
|
- });
|
|
|
-}
|
|
|
-
|
|
|
-- (void)joinChatRoomAndLiveRoom {
|
|
|
-
|
|
|
- [[RCIMClient sharedRCIMClient] joinExistChatRoom:self.roomId messageCount:-1 success:^{
|
|
|
- MJWeakSelf;
|
|
|
- [self leaveRTCRoomCallback:^(BOOL success) {
|
|
|
- dispatch_main_async_safe(^{
|
|
|
- [weakSelf joinRTCRoom];
|
|
|
- });
|
|
|
- }];
|
|
|
-
|
|
|
- } error:^(RCErrorCode status) {
|
|
|
- NSLog(@"error code %zd" ,status);
|
|
|
- }];
|
|
|
-}
|
|
|
-
|
|
|
-- (void)leaveRTCRoomCallback:(void(^)(BOOL success))callback {
|
|
|
- [[RCRTCEngine sharedInstance] leaveRoom:^(BOOL isSuccess, RCRTCCode code) {
|
|
|
- callback(isSuccess);
|
|
|
- }];
|
|
|
-}
|
|
|
-
|
|
|
-- (void)joinRTCRoom {
|
|
|
- [self setRoleType];
|
|
|
-}
|
|
|
-
|
|
|
-- (void)liveroomLogOut {
|
|
|
- if (self.isOtherLogin) {
|
|
|
- return;
|
|
|
- }
|
|
|
- self.isOtherLogin = YES;
|
|
|
- [LOADING_MANAGER MBShowAUTOHidingInWindow:@"该账号在其他设备上登录"];
|
|
|
- [self quitRoomBackPreView:NO];
|
|
|
- dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.5f * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
|
|
|
-
|
|
|
- [[NSNotificationCenter defaultCenter] postNotificationName:@"liveroomBackRefresh" object:nil];
|
|
|
- });
|
|
|
-}
|
|
|
-
|
|
|
-- (void)liveroomQuit {
|
|
|
- if (self.isOtherLogin) {
|
|
|
- return;
|
|
|
- }
|
|
|
- self.isOtherLogin = YES;
|
|
|
- [self quitRoomBackPreView:NO];
|
|
|
- dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.0f * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
|
|
|
- [[NSNotificationCenter defaultCenter] postNotificationName:@"liveroomBackRefresh" object:nil];
|
|
|
- });
|
|
|
-}
|
|
|
-
|
|
|
-- (void)connectionService {
|
|
|
- [self joinChatRoom];
|
|
|
- [self setRoleType];
|
|
|
-}
|
|
|
-
|
|
|
-- (void)countLikeMessageCount {
|
|
|
- NSInteger count = self.likeCount;
|
|
|
- NSString *desc = @"";
|
|
|
- if (count > 10000) {
|
|
|
- count = count / 10000;
|
|
|
- desc = [NSString stringWithFormat:@"本场点赞%zd万+",count];
|
|
|
- }
|
|
|
- else {
|
|
|
- desc = [NSString stringWithFormat:@"本场点赞%zd",count];
|
|
|
- }
|
|
|
- self.headView.likeCount.text = desc;
|
|
|
-}
|
|
|
-- (void)countMemberCount {
|
|
|
- NSInteger count = self.totalCount;
|
|
|
- NSString *desc = @"";
|
|
|
- if (count > 10000) {
|
|
|
- count = count / 10000;
|
|
|
- desc = [NSString stringWithFormat:@"%zd万+人",count];
|
|
|
- }
|
|
|
- else {
|
|
|
- desc = [NSString stringWithFormat:@"%zd人",count];
|
|
|
- }
|
|
|
- self.headView.roomMemberCount.text = desc;
|
|
|
-}
|
|
|
-
|
|
|
-// 刷新seatView
|
|
|
-- (void)renderSeatView {
|
|
|
- NSMutableArray *seatArray = [NSMutableArray array];
|
|
|
- NSArray *remoteUserArray = [self.room.remoteUsers mutableCopy];
|
|
|
- for (RCRTCRemoteUser *user in remoteUserArray) {
|
|
|
- if (![user.userId containsString:@"rc_mc_"]) {
|
|
|
- [seatArray addObject:user.userId];
|
|
|
- }
|
|
|
- }
|
|
|
- if (seatArray.count) {
|
|
|
- if (![self.livePageView.subviews containsObject:self.seatContainer]) {
|
|
|
- [self.livePageView addSubview:self.seatContainer];
|
|
|
- }
|
|
|
-
|
|
|
- [self.seatContainer mas_remakeConstraints:^(MASConstraintMaker *make) {
|
|
|
- make.left.right.mas_equalTo(self.livePageView);
|
|
|
- make.top.mas_equalTo(self.headView.mas_bottom).offset(10);
|
|
|
- make.height.mas_equalTo(80);
|
|
|
- }];
|
|
|
-
|
|
|
- self.seatContainer.seatMemberArray = [NSMutableArray arrayWithArray:seatArray];
|
|
|
- [self.seatContainer refreshSeatUI];
|
|
|
- [self refreshSeatApplyList];
|
|
|
-
|
|
|
- }
|
|
|
- else {
|
|
|
- [self removeSeatContainer];
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
-- (void)refreshSeatApplyList {
|
|
|
- // 查询不在列表的成员
|
|
|
- NSMutableArray *requestArray = [NSMutableArray array];
|
|
|
- NSMutableArray *memberArray = [self.seatContainer.seatMemberArray mutableCopy];
|
|
|
- NSMutableArray *seatApplyArray = [self.seatApplyArray mutableCopy];
|
|
|
- for (NSString *userId in memberArray) {
|
|
|
- BOOL containUser = NO;
|
|
|
- for (LiveSeatMember *member in seatApplyArray) {
|
|
|
- if ([member.userId isEqualToString:userId]) {
|
|
|
- containUser = YES;
|
|
|
- }
|
|
|
- }
|
|
|
- if (containUser == NO) {
|
|
|
- LiveSeatMember *member = [[LiveSeatMember alloc] init];
|
|
|
- member.isConnected = YES;
|
|
|
- member.userId = userId;
|
|
|
- [requestArray addObject:member];
|
|
|
- }
|
|
|
- }
|
|
|
- if (requestArray.count) {
|
|
|
- self.seatApplyArray = [NSMutableArray arrayWithArray:requestArray];
|
|
|
- [self refreshSeatApplyView];
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-- (void)removeSeatContainer {
|
|
|
- if ([self.livePageView.subviews containsObject:self.seatContainer]) {
|
|
|
- [self.seatContainer removeFromSuperview];
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-- (void)setRoleType {
|
|
|
- // 1.设置切换听筒为扬声器
|
|
|
- [[RCRTCEngine sharedInstance] setDefaultAudioRouteToSpeaker:YES];
|
|
|
- [RCRTCEngine sharedInstance].statusReportDelegate = self;
|
|
|
- // 2.添加本地采集预览界面
|
|
|
- [self setupLocalVideoView];
|
|
|
- // 3.加入RTC房间
|
|
|
- [self joinRTCLiveRoom];
|
|
|
-}
|
|
|
-
|
|
|
-// 添加本地采集预览页面
|
|
|
-- (void)setupLocalVideoView {
|
|
|
- [self.liveVideoView addSubview:self.localVideo.canvesView];
|
|
|
- [self.localVideo.canvesView mas_makeConstraints:^(MASConstraintMaker *make) {
|
|
|
- make.left.right.top.bottom.mas_equalTo(self.liveVideoView);
|
|
|
- }];
|
|
|
-}
|
|
|
-
|
|
|
-#pragma mark ----- RCRTCStatusReportDelegate
|
|
|
-- (void)didReportStatusForm:(RCRTCStatusForm *)form {
|
|
|
- BOOL isConnectedFailed = NO;
|
|
|
- for (RCRTCStreamStat* stat in form.sendStats) {
|
|
|
- if (stat.packetLoss == 1.0) {
|
|
|
- isConnectedFailed = YES;
|
|
|
- break;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- [self showNetStatus:form.rtt networkLost:isConnectedFailed];
|
|
|
-
|
|
|
-// NSLog(@"%@",form.description);
|
|
|
- // 网络状态差提示
|
|
|
-
|
|
|
-}
|
|
|
-- (void)showNetStatus:(NSInteger)rttValue networkLost:(BOOL)isFailed {
|
|
|
- dispatch_main_async_safe((^{
|
|
|
- if (isFailed) {
|
|
|
- [self.headView.rttImage setImage:[UIImage imageNamed:@"live_networking_bad"]];
|
|
|
- self.headView.msLabel.text = @"网络已断开";
|
|
|
- }
|
|
|
- else {
|
|
|
- self.headView.msLabel.text = [NSString stringWithFormat:@"%zdms",rttValue];
|
|
|
- if (rttValue < 100) {
|
|
|
- [self.headView.rttImage setImage:[UIImage imageNamed:@"live_networking_good"]];
|
|
|
- }
|
|
|
- else if (rttValue < 200) {
|
|
|
- [self.headView.rttImage setImage:[UIImage imageNamed:@"live_networking_nomal"]];
|
|
|
- }
|
|
|
- else {
|
|
|
- [self.headView.rttImage setImage:[UIImage imageNamed:@"live_networking_bad"]];
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- }));
|
|
|
-}
|
|
|
-
|
|
|
-#pragma mark ---- RCRTCRoomEventDelegate
|
|
|
-// 远端发布流
|
|
|
-- (void)didPublishStreams:(NSArray<RCRTCInputStream *> *)streams {
|
|
|
- [self subscribeRemoteResource:streams];
|
|
|
- NSLog(@"didPublishStreams --------");
|
|
|
-}
|
|
|
-
|
|
|
-// 订阅远端流
|
|
|
-- (void)subscribeRemoteResource:(NSArray<RCRTCInputStream *> *)streams {
|
|
|
- [self subscribeRemoteResource:streams isTiny:NO];
|
|
|
-}
|
|
|
-
|
|
|
-- (void)subscribeRemoteResource:(NSArray<RCRTCInputStream *> *)streams isTiny:(BOOL)isTiny {
|
|
|
- // 订阅房间中远端用户音视频流资源
|
|
|
- NSArray *tinyStream = isTiny ? streams : @[];
|
|
|
- NSArray *ordinaryStream = isTiny ? @[] : streams;
|
|
|
- MJWeakSelf;
|
|
|
- [self.room.localUser subscribeStream:ordinaryStream
|
|
|
- tinyStreams:tinyStream
|
|
|
- completion:^(BOOL isSuccess, RCRTCCode desc) {
|
|
|
- if (desc != RCRTCCodeSuccess) {
|
|
|
- NSString *errorStr = [NSString stringWithFormat:@"订阅远端流失败:%ld", (long) desc];
|
|
|
- [LOADING_MANAGER MBShowAUTOHidingInWindow:errorStr];
|
|
|
- return;
|
|
|
- }
|
|
|
- }];
|
|
|
- [self renderSeatView];
|
|
|
-}
|
|
|
-
|
|
|
-- (void)didUnpublishStreams:(NSArray<RCRTCInputStream *> *)streams {
|
|
|
- NSLog(@"didUnPublishStreams --------");
|
|
|
- [self renderSeatView];
|
|
|
-}
|
|
|
-
|
|
|
-- (void)didOfflineUser:(RCRTCRemoteUser *)user {
|
|
|
- [self renderSeatView];
|
|
|
-}
|
|
|
-- (void)didJoinUser:(RCRTCRemoteUser *)user {
|
|
|
- NSLog(@"--didJoinUser-");
|
|
|
-// [self renderSeatView];
|
|
|
-}
|
|
|
-
|
|
|
-// 如果有远端用户离开房间
|
|
|
-- (void)didLeaveUser:(RCRTCRemoteUser *)user {
|
|
|
- NSLog(@"--didLeaveUser-");
|
|
|
- // 如果有人离开房间
|
|
|
- if ([self judgeContainMember:user.userId]) {
|
|
|
- [self removeMember:user.userId];
|
|
|
- [self refreshSeatApplyView];
|
|
|
- }
|
|
|
- [self renderSeatView];
|
|
|
-}
|
|
|
-
|
|
|
-// 远端用户切换身份
|
|
|
-- (void)didSwitchRoleWithUser:(RCRTCRemoteUser *)user roleType:(RCRTCLiveRoleType)roleType {
|
|
|
- if (roleType == RCRTCLiveRoleTypeBroadcaster) {
|
|
|
- if ([self judgeContainUser:user.userId] == NO) {
|
|
|
- [self.remoteMemberArray addObject:user];
|
|
|
- // 刷新连麦成员状态数据
|
|
|
- if ([self judgeContainMember:user.userId]) {
|
|
|
- // 更新状态
|
|
|
- [self updateMemberStatusConnecting:user.userId];
|
|
|
- [self refreshSeatApplyView];
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- else {
|
|
|
- [self removeMemberUserId:user.userId];
|
|
|
- // 刷新连麦成员数据
|
|
|
- if ([self judgeContainMember:user.userId]) {
|
|
|
- [self removeMember:user.userId];
|
|
|
- [self refreshSeatApplyView];
|
|
|
- }
|
|
|
- [self renderSeatView];
|
|
|
- }
|
|
|
-
|
|
|
- NSLog(@"didSwitchRoleWithUser --------");
|
|
|
-}
|
|
|
-
|
|
|
-- (BOOL)judgeContainUser:(NSString *)userId {
|
|
|
- BOOL containUser = NO;
|
|
|
- for (RCRTCRemoteUser *remoteUser in self.remoteMemberArray) {
|
|
|
- if ([remoteUser.userId isEqualToString:userId]) {
|
|
|
- containUser = YES;
|
|
|
- }
|
|
|
- }
|
|
|
- return containUser;
|
|
|
-}
|
|
|
-
|
|
|
-- (BOOL)getUserConnectStatus:(NSString *)userId {
|
|
|
- BOOL isConnected = NO;
|
|
|
- for (LiveSeatMember *member in self.seatApplyArray) {
|
|
|
- if ([member.userId isEqualToString:userId]) {
|
|
|
- return member.isConnected;
|
|
|
- }
|
|
|
- }
|
|
|
- return isConnected;
|
|
|
-}
|
|
|
-
|
|
|
-- (void)removeMemberUserId:(NSString *)userId {
|
|
|
- for (RCRTCRemoteUser *remoteUser in self.remoteMemberArray) {
|
|
|
- if ([remoteUser.userId isEqualToString:userId]) {
|
|
|
- [self.remoteMemberArray removeObject:remoteUser];
|
|
|
- return;
|
|
|
- }
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-#pragma mark - KSChatInputBarControlDelegate
|
|
|
-// 根据inputBar 回调来修改页面布局
|
|
|
-- (void)onInputBarControlContentSizeChanged:(CGRect)frame withAnimationDuration:(CGFloat)duration andAnimationCurve:(UIViewAnimationCurve)curve {
|
|
|
- CGRect originFrame = _inputBar.frame;
|
|
|
- __weak __typeof(&*self)weakSelf = self;
|
|
|
- // 目前只使用y值即可 -- 只修改messageContentView高度,让展示消息view和输入框随之移动
|
|
|
- [UIView animateWithDuration:duration animations:^{
|
|
|
- [UIView setAnimationCurve:curve];
|
|
|
- [weakSelf.inputBar setFrame:CGRectMake(0, frame.origin.y - originFrame.size.height, originFrame.size.width, originFrame.size.height)];
|
|
|
- [UIView commitAnimations];
|
|
|
- }];
|
|
|
-}
|
|
|
-
|
|
|
-// 发送消息
|
|
|
-- (void)onTouchSendButton:(NSString *)text {
|
|
|
- [self touristSendMessage:text];
|
|
|
-}
|
|
|
-
|
|
|
-- (void)touristSendMessage:(NSString *)text {
|
|
|
-
|
|
|
- RCTextMessage *rcTextMessage = [RCTextMessage messageWithContent:text];
|
|
|
- MJWeakSelf;
|
|
|
- [self sendMessage:rcTextMessage displayMessage:YES callback:^(BOOL success) {
|
|
|
- [weakSelf setDefaultBottomViewStatus];
|
|
|
- }];
|
|
|
-}
|
|
|
-
|
|
|
-#pragma mark ---- RTC
|
|
|
-- (void)joinRTCLiveRoom {
|
|
|
- // 1.配置房间
|
|
|
- RCRTCRoomConfig *config = [[RCRTCRoomConfig alloc] init];
|
|
|
- config.roomType = RCRTCRoomTypeLive;
|
|
|
- config.liveType = RCRTCLiveTypeAudioVideo;
|
|
|
- config.roleType = RCRTCLiveRoleTypeBroadcaster;
|
|
|
- __weak typeof(self) weakSelf = self;
|
|
|
- [[RCRTCEngine sharedInstance] joinRoom:self.roomId config:config completion:^(RCRTCRoom * _Nullable room, RCRTCCode code) {
|
|
|
- dispatch_main_async_safe(^{
|
|
|
- __strong typeof(weakSelf) strongSelf = weakSelf;
|
|
|
- if (code == RCRTCCodeSignalServerNotConnect || code == RCRTCCodeParameterError || code == RCRTCCodeNotInRTCRoom || code == RCRTCCodeRTCTokenIsNull || code == RCRTCCodeHttpTimeoutError || code == RCRTCCodeHttpError || code == RCRTCCodeVoIPNotAvailable) {
|
|
|
- NSLog(@"%@",[NSString stringWithFormat:@"加入失败 code %ld",code]);
|
|
|
- [LOADING_MANAGER MBShowAUTOHidingInWindow:@"加入直播间失败"];
|
|
|
- }
|
|
|
- else {
|
|
|
- [strongSelf notiferJoinSuccessToServiceCallback:^{
|
|
|
-
|
|
|
- }];
|
|
|
- if (room) {
|
|
|
- strongSelf.room = room;
|
|
|
- strongSelf.room.delegate = self;
|
|
|
- if (room.remoteUsers.count) {
|
|
|
- NSMutableArray *streamArray = [NSMutableArray array];
|
|
|
- NSMutableArray *remoteUserArray = [room.remoteUsers mutableCopy];
|
|
|
- for (RCRTCRemoteUser *user in remoteUserArray) {
|
|
|
- if (user.remoteStreams.count) {
|
|
|
- [streamArray addObjectsFromArray:user.remoteStreams];
|
|
|
- }
|
|
|
- }
|
|
|
- // 如果存在远端流 订阅
|
|
|
- if (streamArray.count) {
|
|
|
- [strongSelf subscribeRemoteResource:streamArray];
|
|
|
-
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- // 订阅流数据
|
|
|
- [strongSelf renderSeatView];
|
|
|
-
|
|
|
- [strongSelf countMemberCount];
|
|
|
- // 发布本地视频流
|
|
|
- if (strongSelf.isPauseLive == NO && strongSelf.isEnterBackground == NO) {
|
|
|
- [strongSelf publishLocalStream];
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- });
|
|
|
- }];
|
|
|
-}
|
|
|
-
|
|
|
-- (void)publishLocalStream {
|
|
|
- // 1.设置渲染视图渲染视图
|
|
|
- [[RCRTCEngine sharedInstance].defaultVideoStream setVideoView:self.localVideo.canvesView];
|
|
|
- // 2.设置视频流参数
|
|
|
- RCRTCVideoStreamConfig *videoConfig = [RCRTCEngine sharedInstance].defaultVideoStream.videoConfig;
|
|
|
- videoConfig.videoSizePreset = RCRTCVideoSizePreset1280x720;
|
|
|
- videoConfig.videoFps = RCRTCVideoFPS30;
|
|
|
- videoConfig.maxBitrate = 2200;
|
|
|
- videoConfig.minBitrate = 200;
|
|
|
- [[RCRTCEngine sharedInstance].defaultVideoStream setVideoConfig:videoConfig];
|
|
|
- // 3.开始视频采集
|
|
|
- [[RCRTCEngine sharedInstance].defaultVideoStream startCapture];
|
|
|
- [RCRTCEngine sharedInstance].defaultVideoStream.enableTinyStream = NO;
|
|
|
- [[RCRTCEngine sharedInstance].defaultAudioStream setAudioQuality:RCRTCAudioQualityMusicHigh Scenario:RCRTCAudioScenarioMusicChatRoom];
|
|
|
-
|
|
|
- // 发布本地视频流到房间
|
|
|
- MJWeakSelf;
|
|
|
- [self.room.localUser publishDefaultLiveStreams:^(BOOL isSuccess, RCRTCCode code, RCRTCLiveInfo * _Nullable liveInfo) {
|
|
|
- if (code == RCRTCCodeSuccess) {
|
|
|
- weakSelf.needPublishStream = NO;
|
|
|
- [weakSelf renderSeatView];
|
|
|
- }
|
|
|
- }];
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
-- (void)exitRoomCallback:(void(^)(BOOL success))callback {
|
|
|
- [[RCRTCEngine sharedInstance].defaultVideoStream stopCapture];
|
|
|
- _localVideo = nil;
|
|
|
- _preVideoView = nil;
|
|
|
- _room = nil;
|
|
|
- MJWeakSelf;
|
|
|
- [[RCRTCEngine sharedInstance] leaveRoom:^(BOOL isSuccess, RCRTCCode code) {
|
|
|
- NSLog(@"----- leave code -----%zd",code);
|
|
|
- dispatch_main_async_safe(^{
|
|
|
- [weakSelf sendLeaveMessageCallback:^(BOOL success) {
|
|
|
- callback(success);
|
|
|
- }];
|
|
|
- });
|
|
|
- }];
|
|
|
-}
|
|
|
-
|
|
|
-- (void)uninitEngine {
|
|
|
- [[RCRTCEngine sharedInstance] unInit];
|
|
|
-}
|
|
|
-
|
|
|
-// 销毁房间
|
|
|
-- (void)distoryRoomCallback:(void(^)(BOOL success))callback {
|
|
|
- [[RCRTCEngine sharedInstance].defaultVideoStream stopCapture];
|
|
|
- _localVideo = nil;
|
|
|
- _preVideoView = nil;
|
|
|
- _room = nil;
|
|
|
- __weak typeof(self) weakSelf = self;
|
|
|
- [[RCRTCEngine sharedInstance] leaveRoom:^(BOOL isSuccess, RCRTCCode code) {
|
|
|
- dispatch_main_async_safe(^{
|
|
|
- __strong typeof(weakSelf) strongSelf = weakSelf;
|
|
|
- [strongSelf sendLeaveMessageCallback:^(BOOL success) {
|
|
|
- callback(success);
|
|
|
- }];
|
|
|
- });
|
|
|
- }];
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
-#pragma mark -- 加入直播间和退出直播间回到服务
|
|
|
-- (void)notiferJoinSuccessToServiceCallback:(void(^)(void))callback {
|
|
|
- [KSNetworkingManager liveRoomJoinRoomRequest:KS_GET roomUid:self.roomId success:^(NSDictionary * _Nonnull dic) {
|
|
|
- callback();
|
|
|
- } faliure:^(NSError * _Nonnull error) {
|
|
|
- callback();
|
|
|
- }];
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
-#pragma mark -- 退出直播间回掉服务
|
|
|
-- (void)quitNotiferService {
|
|
|
- [KSNetworkingManager LiveroomQuit:KS_POST success:^(NSDictionary * _Nonnull dic) {
|
|
|
- if ([dic ks_integerValueForKey:@"errCode"] == 0) {
|
|
|
- NSLog(@"success");
|
|
|
- }
|
|
|
- else {
|
|
|
- NSLog(@"----- error %@", [dic ks_stringValueForKey:@"errMsg"]);
|
|
|
- }
|
|
|
- } faliure:^(NSError * _Nonnull error) {
|
|
|
-
|
|
|
- }];
|
|
|
-}
|
|
|
-
|
|
|
-- (void)closeRoomNotiferService {
|
|
|
- [KSNetworkingManager destroyLiveRoomRequest:KS_GET roomUid:self.roomId success:^(NSDictionary * _Nonnull dic) {
|
|
|
- if ([dic ks_integerValueForKey:@"errCode"] == 0) {
|
|
|
- NSLog(@"success");
|
|
|
- }
|
|
|
- else {
|
|
|
- NSLog(@"----- error %@", [dic ks_stringValueForKey:@"errMsg"]);
|
|
|
- }
|
|
|
- } faliure:^(NSError * _Nonnull error) {
|
|
|
-
|
|
|
- }];
|
|
|
-
|
|
|
-}
|
|
|
-
|
|
|
-- (void)sendLeaveMessageCallback:(void(^)(BOOL success))callback {
|
|
|
-
|
|
|
- RCUserInfo *currentUserInfo = [RCIM sharedRCIM].currentUserInfo;
|
|
|
- KSLiveChatroomLeave *leaveMessage = [[KSLiveChatroomLeave alloc] init];
|
|
|
- leaveMessage.userId = currentUserInfo.userId;
|
|
|
- leaveMessage.userName = currentUserInfo.name;
|
|
|
- [self sendMessage:leaveMessage displayMessage:NO callback:^(BOOL success) {
|
|
|
- callback(success);
|
|
|
- }];
|
|
|
-}
|
|
|
-
|
|
|
-- (void)quitChatRoom {
|
|
|
- [[RCIMClient sharedRCIMClient] quitChatRoom:self.roomId success:^{
|
|
|
- NSLog(@"sucess log out--");
|
|
|
- } error:^(RCErrorCode status) {
|
|
|
- NSLog(@"RCErrorCode------%ld ", (long)status);
|
|
|
- }];
|
|
|
-}
|
|
|
-
|
|
|
-- (void)addConstMessage { // 固定欢迎词语
|
|
|
- RCTextMessage *statement = [RCTextMessage messageWithContent:@"欢迎进入直播课堂,请遵守相关法规,禁止传播低俗、暴力等不良信息。为孩子创造健康绿色的学习环境。"];
|
|
|
- statement.extra = @"statement";
|
|
|
- RCMessage *constMessage = [[RCMessage alloc] initWithType:ConversationType_CHATROOM targetId:self.roomId direction:MessageDirection_SEND content:statement];
|
|
|
- constMessage.content.senderUserInfo = [RCIM sharedRCIM].currentUserInfo;
|
|
|
- [self appendAndDisplayMessage:constMessage];
|
|
|
-}
|
|
|
-
|
|
|
-#pragma mark - views init
|
|
|
-/**
|
|
|
- * 接收到消息的回调
|
|
|
- */
|
|
|
-- (void)didReceiveMessageNotification:(NSNotification *)notification {
|
|
|
- NSDictionary *dic = notification.object;
|
|
|
- __block RCMessage *rcMessage = dic[@"message"];
|
|
|
- KSRCMessageModel *model = [[KSRCMessageModel alloc] initWithMessage:rcMessage];
|
|
|
- model.userInfo = rcMessage.content.senderUserInfo;
|
|
|
- if (model.conversationType == ConversationType_CHATROOM && [model.targetId isEqualToString:self.roomId]) {
|
|
|
- __weak typeof(&*self) __blockSelf = self;
|
|
|
- dispatch_main_async_safe((^{
|
|
|
- // 对赞消息拦截 ,展示动画,不插入数据源 ,对于seat消息 和踢出消息,弹出alert
|
|
|
- if (rcMessage) {
|
|
|
- // 👍🏻消息
|
|
|
- if ([rcMessage.content isMemberOfClass:[KSLiveChatroomLike class]]) {
|
|
|
- KSLiveChatroomLike *likeMessage = (KSLiveChatroomLike *)rcMessage.content;
|
|
|
- // 统计点赞数量
|
|
|
- __blockSelf.likeCount += likeMessage.counts;
|
|
|
- [__blockSelf countLikeMessageCount];
|
|
|
- }
|
|
|
- else if ([rcMessage.content isMemberOfClass:[KSLiveChatroomWelcome class]]) {
|
|
|
- // 过滤自己发送的欢迎消息
|
|
|
- if ([rcMessage.senderUserId isEqualToString:UserDefault(UIDKey)]) {
|
|
|
- return;
|
|
|
- }
|
|
|
- // 弹幕
|
|
|
- RCUserInfo *userInfo = rcMessage.content.senderUserInfo;
|
|
|
- NSString *userName = [userInfo.name stringByAppendingString:@""];
|
|
|
- NSString *contentMsg = [NSString stringWithFormat:@"%@ 进入直播间",userName];
|
|
|
- [__blockSelf showAnimationView:YES showMessag:contentMsg];
|
|
|
-
|
|
|
- if ([__blockSelf judgeContainMember:rcMessage.senderUserId]) {
|
|
|
- [__blockSelf removeMember:rcMessage.senderUserId];
|
|
|
- [__blockSelf refreshSeatApplyView];
|
|
|
- [__blockSelf renderSeatView];
|
|
|
- }
|
|
|
- }
|
|
|
- else if ([rcMessage.content isMemberOfClass:[KSLiveChatroomMemberUp class]]) {
|
|
|
- KSLiveChatroomMemberUp *member = (KSLiveChatroomMemberUp *)rcMessage.content;
|
|
|
- __blockSelf.totalCount = member.count;
|
|
|
- [__blockSelf countMemberCount];
|
|
|
- }
|
|
|
- // 用户退出消息
|
|
|
- else if ([rcMessage.content isMemberOfClass:[KSLiveChatroomLeave class]]) {
|
|
|
- KSLiveChatroomLeave *memberLeaveMsg = (KSLiveChatroomLeave *)rcMessage.content;
|
|
|
- if ([__blockSelf judgeContainMember:memberLeaveMsg.userId]) {
|
|
|
- [__blockSelf removeMember:memberLeaveMsg.userId];
|
|
|
- [__blockSelf refreshSeatApplyView];
|
|
|
- }
|
|
|
- return;
|
|
|
- }
|
|
|
- // 连麦申请消息
|
|
|
- else if ([rcMessage.content isMemberOfClass:[KSLiveChatroomSeatApply class]]) {
|
|
|
- KSLiveChatroomSeatApply *seatApplyMessage = (KSLiveChatroomSeatApply *)rcMessage.content;
|
|
|
-
|
|
|
- if (seatApplyMessage.type == SEATHANDLE_APPLY) { // 观众申请 加入申请中
|
|
|
- LiveSeatMember *member = [[LiveSeatMember alloc] init];
|
|
|
- member.avatar = seatApplyMessage.audienceAvatar;
|
|
|
- member.name = seatApplyMessage.audienceName;
|
|
|
- member.userId = seatApplyMessage.audienceId;
|
|
|
- member.isConnected = NO;
|
|
|
- if (![__blockSelf judgeContainMember:member.userId]) {
|
|
|
- [__blockSelf.seatApplyArray addObject:member];
|
|
|
- [__blockSelf refreshSeatApplyView];
|
|
|
- }
|
|
|
- }
|
|
|
- else if (seatApplyMessage.type == SEATHANDLE_CANCELAPPLY) { // 观众取消申请 从申请中剔除
|
|
|
- if ([__blockSelf judgeContainMember:seatApplyMessage.audienceId]) {
|
|
|
- // 如果在申请中的状态
|
|
|
- BOOL connectedStatus = [__blockSelf getUserConnectStatus:seatApplyMessage.audienceId];
|
|
|
- if (connectedStatus == NO) {
|
|
|
- NSLog(@"hahahhahah");
|
|
|
- [__blockSelf removeMember:seatApplyMessage.audienceId];
|
|
|
- [__blockSelf refreshSeatApplyView];
|
|
|
- }
|
|
|
-
|
|
|
- }
|
|
|
- }
|
|
|
- return;
|
|
|
- }
|
|
|
- // 连麦回复消息(暂不处理)
|
|
|
- else if ([rcMessage.content isMemberOfClass:[KSLiveChatroomSeatResponse class]]) {
|
|
|
-
|
|
|
- }
|
|
|
- else if ([rcMessage.content isMemberOfClass:[KSLiveChatroomDownSeat class]]) { // 观众下麦,从列表中移除
|
|
|
- KSLiveChatroomDownSeat *downSeatMessage = (KSLiveChatroomDownSeat *)rcMessage.content;
|
|
|
- if ([__blockSelf judgeContainMember:downSeatMessage.audienceId]) {
|
|
|
- [__blockSelf removeMember:downSeatMessage.audienceId];
|
|
|
- [__blockSelf refreshSeatApplyView];
|
|
|
- }
|
|
|
- return;
|
|
|
- }
|
|
|
- else if ([rcMessage.content isMemberOfClass:[KSRCShopRushMessage class]]) {
|
|
|
- KSRCShopRushMessage *rushMsg = (KSRCShopRushMessage *)rcMessage.content;
|
|
|
-
|
|
|
- NSString *contentMsg = [NSString stringWithFormat:@"%@ 正在抢购",[NSString returnNoNullStringWithString:rushMsg.userName]];
|
|
|
- [__blockSelf showAnimationView:NO showMessag:contentMsg];
|
|
|
- }
|
|
|
- else if ([rcMessage.content isMemberOfClass:[RCTextMessage class]]) {
|
|
|
- [__blockSelf insertMessage:rcMessage userInfo:notification.userInfo];
|
|
|
- }
|
|
|
- else if ([rcMessage.content isMemberOfClass:[KSLiveChatroomClose class]]) { // 直播间已关闭
|
|
|
- [LOADING_MANAGER MBShowAUTOHidingInWindow:@"直播已结束"];
|
|
|
- dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.0f * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
|
|
|
- // 退出直播间
|
|
|
- [__blockSelf quitRoomBackPreView:NO];
|
|
|
- });
|
|
|
- return;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- }));
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-- (void)insertMessage:(RCMessage *)rcMessage userInfo:(NSDictionary *)userInfo {
|
|
|
- // left
|
|
|
- NSDictionary *leftDic = userInfo;
|
|
|
- if (leftDic && [leftDic[@"left"] isEqual:@(0)]) {
|
|
|
- self.isNeedScrollToButtom = YES;
|
|
|
- }
|
|
|
- [self appendAndDisplayMessage:rcMessage];
|
|
|
-}
|
|
|
-
|
|
|
-- (BOOL)judgeContainMember:(NSString *)userId {
|
|
|
- for (LiveSeatMember *obj in self.seatApplyArray) {
|
|
|
- if ([obj.userId isEqualToString:userId]) {
|
|
|
- return YES;
|
|
|
- }
|
|
|
- }
|
|
|
- return NO;
|
|
|
-}
|
|
|
-
|
|
|
-- (NSInteger)queryConnectingCount {
|
|
|
- NSInteger count = 0;
|
|
|
- for (LiveSeatMember *member in self.seatApplyArray) {
|
|
|
- if (member.isConnected) {
|
|
|
- count++;
|
|
|
- }
|
|
|
- }
|
|
|
- return count;
|
|
|
-}
|
|
|
-
|
|
|
-- (void)removeMember:(NSString *)memberId {
|
|
|
- for (LiveSeatMember *member in self.seatApplyArray) {
|
|
|
- if ([member.userId isEqualToString:memberId]) {
|
|
|
- [self.seatApplyArray removeObject:member];
|
|
|
- return;
|
|
|
- }
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-- (void)updateMemberStatusWaiting:(NSString *)userId {
|
|
|
- for (LiveSeatMember *obj in self.seatApplyArray) {
|
|
|
- if ([obj.userId isEqualToString:userId]) {
|
|
|
- obj.isConnected = NO;
|
|
|
- return;
|
|
|
- }
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-- (void)updateMemberStatusConnecting:(NSString *)userId {
|
|
|
- for (LiveSeatMember *obj in self.seatApplyArray) {
|
|
|
- if ([obj.userId isEqualToString:userId]) {
|
|
|
- obj.isConnected = YES;
|
|
|
- return;
|
|
|
- }
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-- (void)refreshSeatApplyView {
|
|
|
- if (self.seatApplyArray.count) {
|
|
|
- NSInteger count = 0;
|
|
|
- for (LiveSeatMember *obj in self.seatApplyArray) {
|
|
|
- if (obj.isConnected == NO) {
|
|
|
- count++;
|
|
|
- }
|
|
|
- }
|
|
|
- if (count > 0) {
|
|
|
- [self showSeatTips:count];
|
|
|
- }
|
|
|
- else {
|
|
|
- [self hideSeatTips];
|
|
|
- }
|
|
|
- }
|
|
|
- else {
|
|
|
- [self hideSeatTips];
|
|
|
- }
|
|
|
- [self.seatActionView refreshSeatApplyTable:self.seatApplyArray];
|
|
|
-}
|
|
|
-
|
|
|
-- (void)showSeatTips:(NSInteger)count {
|
|
|
- NSString *countDesc = count >= 100 ? @"99+" : [NSString stringWithFormat:@"%zd",count];
|
|
|
- [self.seatApplyTips configCountMessage:countDesc];
|
|
|
- [self.seatApplyTips showTipsView];
|
|
|
-}
|
|
|
-
|
|
|
-- (void)hideSeatTips {
|
|
|
- [self.seatApplyTips hideView];
|
|
|
-}
|
|
|
-// 发送人数同步消息
|
|
|
-- (void)sendMemberCountMessage {
|
|
|
- KSLiveChatroomMemberCount *syncMessage = [[KSLiveChatroomMemberCount alloc] init];
|
|
|
- syncMessage.count = self.totalCount;
|
|
|
-
|
|
|
- [self sendMessage:syncMessage displayMessage:NO callback:^(BOOL success) {
|
|
|
-
|
|
|
- }];
|
|
|
-}
|
|
|
-
|
|
|
-#pragma mark ----- time manager delegate
|
|
|
-- (void)formatTime:(NSString *)timeString {
|
|
|
- self.headView.timeLabel.text = timeString;
|
|
|
-}
|
|
|
-
|
|
|
-- (void)timeLabelAddAnimation:(CABasicAnimation *)animation {
|
|
|
- self.headView.timeLabel.textColor = HexRGB(0x2DC7AA);
|
|
|
-// [self.headView.timeLabel.layer addAnimation:animation forKey:nil];
|
|
|
-}
|
|
|
-
|
|
|
-//- (void)quitClassroomNotifer {
|
|
|
-// [LOADING_MANAGER MBShowAUTOHidingInWindow:@"直播已结束!"];
|
|
|
-// dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.5f * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
|
|
|
-// [self quitRoomBackPreView:NO];
|
|
|
-// });
|
|
|
-//}
|
|
|
-
|
|
|
-#pragma mark - gesture and button action
|
|
|
-- (void)resetBottomGesture:(UIGestureRecognizer *)gestureRecognizer {
|
|
|
- if (gestureRecognizer.state == UIGestureRecognizerStateEnded) {
|
|
|
- [self setDefaultBottomViewStatus];
|
|
|
- }
|
|
|
-}
|
|
|
-- (void)setDefaultBottomViewStatus {
|
|
|
- [self.inputBar setInputBarStatus:KSBottomBarStatusDefault];
|
|
|
- [self.inputBar setHidden:YES];
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
-#pragma mark ---- sendMessage/showMessage
|
|
|
-- (void)sendMessage:(RCMessageContent *)messageContent displayMessage:(BOOL)displayMessage callback:(void(^)(BOOL success))callback {
|
|
|
- if (_roomId == nil) {
|
|
|
- return;
|
|
|
- }
|
|
|
- messageContent.senderUserInfo = [RCIM sharedRCIM].currentUserInfo;
|
|
|
- if (messageContent == nil) {
|
|
|
- return;
|
|
|
- }
|
|
|
- __weak typeof(&*self) __weakself = self;
|
|
|
- [KSChatroomMessageCenter sendChatMessage:self.roomId content:messageContent success:^(long messageId) {
|
|
|
- dispatch_async(dispatch_get_main_queue(), ^{
|
|
|
- RCMessage *message = [[RCMessage alloc] initWithType:ConversationType_CHATROOM targetId:__weakself.roomId direction:MessageDirection_SEND content:messageContent];
|
|
|
- message.content.senderUserInfo = [RCIM sharedRCIM].currentUserInfo;
|
|
|
-
|
|
|
- message.senderUserId = UserDefault(UIDKey);
|
|
|
- if (displayMessage) {
|
|
|
- [__weakself appendAndDisplayMessage:message];
|
|
|
- }
|
|
|
- [__weakself.inputBar clearInputView];
|
|
|
- callback(YES);
|
|
|
- });
|
|
|
-
|
|
|
- } error:^(RCErrorCode errorCode, long messageId) {
|
|
|
- if (errorCode == RC_CHATROOM_NOT_EXIST) {
|
|
|
- dispatch_async(dispatch_get_main_queue(), ^{
|
|
|
- [LOADING_MANAGER MBShowAUTOHidingInWindow:@"聊天已被解散,请退出后重进。"];
|
|
|
- });
|
|
|
- }
|
|
|
- dispatch_async(dispatch_get_main_queue(), ^{
|
|
|
- [__weakself.inputBar clearInputView];
|
|
|
- NSLog(@"发送失败,errorcode is: %ld",(long)errorCode);
|
|
|
- callback(NO);
|
|
|
- });
|
|
|
- }];
|
|
|
-}
|
|
|
-
|
|
|
-/**
|
|
|
- * 将消息加入本地数组
|
|
|
- */
|
|
|
-- (void)appendAndDisplayMessage:(RCMessage *)rcMessage {
|
|
|
- if (!rcMessage) {
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- KSRCMessageModel *model = [[KSRCMessageModel alloc] initWithMessage:rcMessage];
|
|
|
- model.userInfo = rcMessage.content.senderUserInfo;
|
|
|
- if (!model.userInfo) {
|
|
|
- model.userInfo = [RCIMClient sharedRCIMClient].currentUserInfo;
|
|
|
- }
|
|
|
-
|
|
|
- if ([self appendMessageModel:model]) {
|
|
|
- NSIndexPath *indexPath =
|
|
|
- [NSIndexPath indexPathForItem:self.conversationDataRepository.count - 1
|
|
|
- inSection:0];
|
|
|
- if ([self.conversationMessageTableView numberOfRowsInSection:0] !=
|
|
|
- self.conversationDataRepository.count - 1) {
|
|
|
- return;
|
|
|
- }
|
|
|
- // view刷新
|
|
|
- [self.conversationMessageTableView insertRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationNone];
|
|
|
- if ([self isAtTheBottomOfTableView] || self.isNeedScrollToButtom) {
|
|
|
- [self scrollToBottomAnimated:YES];
|
|
|
- self.isNeedScrollToButtom=NO;
|
|
|
- }
|
|
|
- }
|
|
|
- return;
|
|
|
-}
|
|
|
-
|
|
|
-/**
|
|
|
- * 如果当前会话没有这个消息id,把消息加入本地数组
|
|
|
- */
|
|
|
-- (BOOL)appendMessageModel:(KSRCMessageModel *)model {
|
|
|
-
|
|
|
- if (!model.content) {
|
|
|
- return NO;
|
|
|
- }
|
|
|
- //这里可以根据消息类型来决定是否显示,如果不希望显示直接return NO
|
|
|
-
|
|
|
- //数量不可能无限制的大,这里限制收到消息过多时,就对显示消息数量进行限制。
|
|
|
- //用户可以手动下拉更多消息,查看更多历史消息。
|
|
|
- if (self.conversationDataRepository.count>100) {
|
|
|
- // NSRange range = NSMakeRange(0, 1);
|
|
|
- KSRCMessageModel *message = self.conversationDataRepository[0];
|
|
|
- [[RCIMClient sharedRCIMClient]deleteMessages:@[@(message.messageId)]];
|
|
|
- [self.conversationDataRepository removeObjectAtIndex:0];
|
|
|
- [self.conversationMessageTableView reloadData];
|
|
|
- }
|
|
|
-
|
|
|
- [self.conversationDataRepository addObject:model];
|
|
|
- return YES;
|
|
|
-}
|
|
|
-
|
|
|
-/**
|
|
|
- * 判断消息是否在collectionView的底部
|
|
|
- *
|
|
|
- * @return 是否在底部
|
|
|
- */
|
|
|
-- (BOOL)isAtTheBottomOfTableView {
|
|
|
- if (self.conversationMessageTableView.contentSize.height <= self.conversationMessageTableView.frame.size.height) {
|
|
|
- return YES;
|
|
|
- }
|
|
|
- if(self.conversationMessageTableView.contentOffset.y +200 >= (self.conversationMessageTableView.contentSize.height - self.conversationMessageTableView.frame.size.height)) {
|
|
|
- return YES;
|
|
|
- }else{
|
|
|
- return NO;
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-/**
|
|
|
- * 消息滚动到底部
|
|
|
- *
|
|
|
- * @param animated 是否开启动画效果
|
|
|
- */
|
|
|
-- (void)scrollToBottomAnimated:(BOOL)animated {
|
|
|
- if ([self.conversationMessageTableView numberOfSections] == 0) {
|
|
|
- return;
|
|
|
- }
|
|
|
- NSUInteger finalRow = MAX(0, [self.conversationMessageTableView numberOfRowsInSection:0] - 1);
|
|
|
- if (0 == finalRow) {
|
|
|
- return;
|
|
|
- }
|
|
|
- NSIndexPath *finalIndexPath =
|
|
|
- [NSIndexPath indexPathForItem:finalRow inSection:0];
|
|
|
- [self.conversationMessageTableView scrollToRowAtIndexPath:finalIndexPath atScrollPosition:UITableViewScrollPositionTop animated:animated];
|
|
|
-}
|
|
|
-/*
|
|
|
-#pragma mark - Navigation
|
|
|
-
|
|
|
-// In a storyboard-based application, you will often want to do a little preparation before navigation
|
|
|
-- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
|
|
|
- // Get the new view controller using [segue destinationViewController].
|
|
|
- // Pass the selected object to the new view controller.
|
|
|
-}
|
|
|
-*/
|
|
|
-
|
|
|
-#pragma mark ----- table data source
|
|
|
-- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
|
|
|
- return self.conversationDataRepository.count;
|
|
|
-}
|
|
|
-
|
|
|
-- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
|
|
|
- KSRCMessageModel *model = [self.conversationDataRepository objectAtIndex:indexPath.row];
|
|
|
- RCMessageContent *messageContent = model.content;
|
|
|
- KSChatroomTextCell *cell = [tableView dequeueReusableCellWithIdentifier:@"KSChatroomTextCell"];
|
|
|
- if(!cell){
|
|
|
- cell = [[KSChatroomTextCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"KSChatroomTextCell"];
|
|
|
- }
|
|
|
- if ([messageContent isMemberOfClass:[RCTextMessage class]] || [messageContent isMemberOfClass:[KSLiveChatroomWelcome class]] || [messageContent isMemberOfClass:[KSLiveChatroomLike class]] || [messageContent isMemberOfClass:[KSLiveChatroomSeatApply class]] || [messageContent isMemberOfClass:[KSLiveChatroomSeatResponse class]]){
|
|
|
- [cell setDataModel:model createrId:self.createrId];
|
|
|
- }
|
|
|
- return cell;
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
-#pragma mark --- lazying
|
|
|
-- (UIView *)livePageView {
|
|
|
- if (!_livePageView) {
|
|
|
- _livePageView = [[UIView alloc] init];
|
|
|
- _livePageView.backgroundColor = HexRGB(0x25292e);
|
|
|
- }
|
|
|
- return _livePageView;
|
|
|
-}
|
|
|
-
|
|
|
-- (UIView *)liveVideoView {
|
|
|
- if (!_liveVideoView) {
|
|
|
- _liveVideoView = [[UIView alloc] init];
|
|
|
- _liveVideoView.backgroundColor = [UIColor clearColor];
|
|
|
- }
|
|
|
- return _liveVideoView;
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
-- (LiveRoomHeadView *)headView {
|
|
|
- if (!_headView) {
|
|
|
- _headView = [LiveRoomHeadView shareInstance];
|
|
|
- MJWeakSelf;
|
|
|
- [_headView liveHeaderAction:^{
|
|
|
- [weakSelf switchCamera];
|
|
|
- }];
|
|
|
- }
|
|
|
- return _headView;
|
|
|
-}
|
|
|
-
|
|
|
-- (void)switchCamera {
|
|
|
- [[RCRTCEngine sharedInstance].defaultVideoStream switchCamera];
|
|
|
-}
|
|
|
-
|
|
|
-- (LiveRoomBottomView *)bottomView {
|
|
|
- if (!_bottomView) {
|
|
|
- _bottomView = [LiveRoomBottomView shareInstance];
|
|
|
- MJWeakSelf;
|
|
|
- [_bottomView bottomClickAction:^(LIVEROOMACTION action) {
|
|
|
- [weakSelf bottomViewAction:action];
|
|
|
- }];
|
|
|
- }
|
|
|
- return _bottomView;
|
|
|
-}
|
|
|
-
|
|
|
-- (void)bottomViewAction:(LIVEROOMACTION)action {
|
|
|
- switch (action) {
|
|
|
- case LIVEROOMACTION_CHAT: // 聊天
|
|
|
- {
|
|
|
- [_inputBar setHidden:NO];
|
|
|
- [_inputBar setInputBarStatus:KSBottomBarStatusKeyboard];
|
|
|
- }
|
|
|
- break;
|
|
|
- case LIVEROOMACTION_SEAT: // 呼出连麦页面
|
|
|
- {
|
|
|
- [self displaySeatView];
|
|
|
- }
|
|
|
- break;
|
|
|
-// case LIVEROOMACTION_QUIT: // 退出
|
|
|
-// {
|
|
|
-// [self showMoreView];
|
|
|
-// }
|
|
|
- break;
|
|
|
- case LIVEROOMACTION_MICACTION:
|
|
|
- {
|
|
|
- self.micEnable = !self.micEnable;
|
|
|
- [[RCRTCEngine sharedInstance].defaultAudioStream setMicrophoneDisable:!self.micEnable];
|
|
|
- NSString *desc = @"";
|
|
|
- if (self.micEnable) {
|
|
|
- desc = @"你已开启麦克风";
|
|
|
- }
|
|
|
- else {
|
|
|
- desc = @"你已关闭麦克风";
|
|
|
- }
|
|
|
- [LOADING_MANAGER MBShowAUTOHidingInWindow:desc];
|
|
|
- }
|
|
|
- break;
|
|
|
- default:
|
|
|
- break;
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-- (void)setMicEnable:(BOOL)micEnable {
|
|
|
- _micEnable = micEnable;
|
|
|
- self.bottomView.isMicOn = micEnable;
|
|
|
-}
|
|
|
-
|
|
|
-- (void)showMoreView {
|
|
|
- [self.view addSubview:self.moreView];
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
-- (SeatTipsView *)seatApplyTips {
|
|
|
- if (!_seatApplyTips) {
|
|
|
- _seatApplyTips = [[SeatTipsView alloc] init];
|
|
|
- }
|
|
|
- return _seatApplyTips;
|
|
|
-}
|
|
|
-- (void)displaySeatView {
|
|
|
- [self.view addSubview:self.seatCtrlView];
|
|
|
- [self refreshSeatApplyView];
|
|
|
-}
|
|
|
-
|
|
|
-- (void)closeRoomAction {
|
|
|
- MJWeakSelf;
|
|
|
- self.alertView = [LiveRoomAlertView liveroomAlertWithTitle:@"结束直播后,不可再次开启" leftButtonTitle:@"取消" rightTitle:@"结束直播" inView:self.view cancel:^{
|
|
|
-
|
|
|
- } confirm:^{
|
|
|
- [weakSelf distoryRoomAction];
|
|
|
- }];
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
-- (void)pauseAction {
|
|
|
- MJWeakSelf;
|
|
|
- self.alertView = [LiveRoomAlertView liveroomAlertWithTitle:@"暂停后观众将无法看到视频画面" leftButtonTitle:@"取消" rightTitle:@"暂停直播" inView:self.view cancel:^{
|
|
|
-
|
|
|
- } confirm:^{
|
|
|
- [weakSelf quitRoomBackPreView:YES];
|
|
|
- }];
|
|
|
-}
|
|
|
-
|
|
|
-- (void)distoryRoomAction {
|
|
|
- MJWeakSelf;
|
|
|
- [self distoryRoomCallback:^(BOOL success) {
|
|
|
- [weakSelf closeRoomNotiferService];
|
|
|
- [weakSelf quitChatRoom];
|
|
|
- weakSelf.room = nil;
|
|
|
- if (self.callback) {
|
|
|
- self.callback();
|
|
|
- }
|
|
|
- [weakSelf.navigationController dismissViewControllerAnimated:YES completion:nil];
|
|
|
-
|
|
|
- }];
|
|
|
-}
|
|
|
-- (void)pauseLiveActionBack:(BOOL)backPreView {
|
|
|
- self.needPublishStream = NO;
|
|
|
- KSRCPauseLiveMessage *pauseMsg = [[KSRCPauseLiveMessage alloc] init];
|
|
|
- MJWeakSelf;
|
|
|
- [self sendMessage:pauseMsg displayMessage:NO callback:^(BOOL success) {
|
|
|
- if (backPreView) {
|
|
|
- [weakSelf.moreView hideView];
|
|
|
- weakSelf.isPauseLive = YES;
|
|
|
- weakSelf.pageType = LIVEPAGE_PREVIEW;
|
|
|
- [weakSelf.livePageView removeFromSuperview];
|
|
|
- [weakSelf configEngine];
|
|
|
- }
|
|
|
- }];
|
|
|
-
|
|
|
- [self.room.localUser unpublishDefaultLiveStreams:^(BOOL isSuccess, RCRTCCode code) {
|
|
|
- if (isSuccess) {
|
|
|
-
|
|
|
- }
|
|
|
- }];
|
|
|
-}
|
|
|
-
|
|
|
-- (void)quitRoomBackPreView:(BOOL)backPreView {
|
|
|
-
|
|
|
- if (backPreView) { // 暂停
|
|
|
- [self pauseLiveActionBack:YES];
|
|
|
- }
|
|
|
- else {
|
|
|
- if (self.pageType == LIVEPAGE_PREVIEW && self.isPauseLive == NO) {
|
|
|
- self.room = nil;
|
|
|
- self.preVideoView = nil;
|
|
|
- [[RCRTCEngine sharedInstance].defaultVideoStream stopCapture];
|
|
|
- if (self.callback) {
|
|
|
- self.callback();
|
|
|
- }
|
|
|
- [self.navigationController dismissViewControllerAnimated:YES completion:nil];
|
|
|
-
|
|
|
- }
|
|
|
- else {
|
|
|
- MJWeakSelf;
|
|
|
- [self exitRoomCallback:^(BOOL success) {
|
|
|
- // quit 接口
|
|
|
- [weakSelf quitNotiferService];
|
|
|
- [weakSelf quitChatRoom];
|
|
|
- [weakSelf.moreView hideView];
|
|
|
- if (weakSelf.callback) {
|
|
|
- weakSelf.callback();
|
|
|
- }
|
|
|
- dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5f * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
|
|
|
- [weakSelf.navigationController dismissViewControllerAnimated:YES completion:nil];
|
|
|
- });
|
|
|
- }];
|
|
|
- }
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-- (KSLiveStreamVideo *)localVideo {
|
|
|
- if (!_localVideo) {
|
|
|
- _localVideo = [KSLiveStreamVideo LocalStreamVideo];
|
|
|
- }
|
|
|
- return _localVideo;
|
|
|
-}
|
|
|
-
|
|
|
-- (NSMutableArray *)remoteMemberArray {
|
|
|
- if (!_remoteMemberArray) {
|
|
|
- _remoteMemberArray = [NSMutableArray array];
|
|
|
- }
|
|
|
- return _remoteMemberArray;
|
|
|
-}
|
|
|
-
|
|
|
-- (UIView *)messageContentView {
|
|
|
- if (!_messageContentView) {
|
|
|
- _messageContentView = [[UIView alloc] init];
|
|
|
- [_messageContentView setBackgroundColor: [UIColor clearColor]];
|
|
|
- }
|
|
|
- return _messageContentView;
|
|
|
-}
|
|
|
-
|
|
|
-- (NSMutableArray<KSRCMessageModel *> *)conversationDataRepository {
|
|
|
- if (!_conversationDataRepository) {
|
|
|
- _conversationDataRepository = [NSMutableArray array];
|
|
|
- }
|
|
|
- return _conversationDataRepository;
|
|
|
-}
|
|
|
-- (KSChatInputBarControl *)inputBar {
|
|
|
- if (!_inputBar) {
|
|
|
- _inputBar = [[KSChatInputBarControl alloc] initWithStatus:KSBottomBarStatusDefault];
|
|
|
- [_inputBar setDelegate:self];
|
|
|
- }
|
|
|
- return _inputBar;
|
|
|
-}
|
|
|
-
|
|
|
-- (UITableView *)conversationMessageTableView {
|
|
|
- if (!_conversationMessageTableView) {
|
|
|
- _conversationMessageTableView = [[UITableView alloc] initWithFrame:CGRectZero style:UITableViewStylePlain];
|
|
|
- _conversationMessageTableView.backgroundColor = [UIColor clearColor];
|
|
|
- _conversationMessageTableView.separatorStyle = UITableViewCellSeparatorStyleNone;
|
|
|
- _conversationMessageTableView.dataSource = self;
|
|
|
- _conversationMessageTableView.delegate = self;
|
|
|
- _conversationMessageTableView.rowHeight = UITableViewAutomaticDimension;
|
|
|
- _conversationMessageTableView.estimatedRowHeight = 40.0f;
|
|
|
- _conversationMessageTableView.showsVerticalScrollIndicator = NO;
|
|
|
- [_conversationMessageTableView registerClass:[KSChatroomTextCell class] forCellReuseIdentifier:@"KSChatroomTextCell"];
|
|
|
- }
|
|
|
- return _conversationMessageTableView;
|
|
|
-}
|
|
|
-
|
|
|
-- (SeatContentView *)seatContainer {
|
|
|
- if (!_seatContainer) {
|
|
|
- _seatContainer = [[SeatContentView alloc] init];
|
|
|
- }
|
|
|
- return _seatContainer;
|
|
|
-}
|
|
|
-
|
|
|
-- (UIView *)seatCtrlView {
|
|
|
- if (!_seatCtrlView) {
|
|
|
- _seatCtrlView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, KPortraitWidth, KPortraitHeight)];
|
|
|
- _seatCtrlView.backgroundColor = [UIColor clearColor];
|
|
|
- self.gesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(hideSeatCtrlView)];
|
|
|
- self.gesture.delegate = self;
|
|
|
- [_seatCtrlView addGestureRecognizer:self.gesture];
|
|
|
- [_seatCtrlView addSubview:self.seatActionView];
|
|
|
- UIView *headView = [[UIView alloc] initWithFrame:CGRectMake(0, KPortraitHeight - 300 - iPhoneXSafeBottomMargin - 16, KPortraitWidth, 16)];
|
|
|
- headView.backgroundColor = [UIColor whiteColor];
|
|
|
- [_seatCtrlView addSubview:headView];
|
|
|
- if (@available(iOS 11.0, *)) {
|
|
|
- headView.layer.cornerRadius = 8;
|
|
|
- headView.layer.maskedCorners = kCALayerMinXMinYCorner | kCALayerMaxXMinYCorner; // 左上圆角
|
|
|
- }
|
|
|
- else {
|
|
|
- UIBezierPath * path = [UIBezierPath bezierPathWithRoundedRect:headView.bounds byRoundingCorners:UIRectCornerTopLeft | UIRectCornerTopRight cornerRadii:CGSizeMake(8, 8)];
|
|
|
- CAShapeLayer *maskLayer = [[CAShapeLayer alloc] init];
|
|
|
- maskLayer.frame = headView.bounds;
|
|
|
- maskLayer.path = path.CGPath;
|
|
|
- headView.layer.mask = maskLayer;
|
|
|
- }
|
|
|
-
|
|
|
- }
|
|
|
- return _seatCtrlView;
|
|
|
-}
|
|
|
-
|
|
|
-- (void)hideSeatCtrlView {
|
|
|
- if (_seatCtrlView) {
|
|
|
- [_seatCtrlView removeFromSuperview];
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch {
|
|
|
- if (gestureRecognizer == self.gesture) {
|
|
|
- if ([touch.view isDescendantOfView:self.seatActionView]) {
|
|
|
- return NO;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- return YES;
|
|
|
-}
|
|
|
-
|
|
|
-- (LiveSeatActionView *)seatActionView {
|
|
|
- if (!_seatActionView) {
|
|
|
- _seatActionView = [[LiveSeatActionView alloc] initWithFrame:CGRectMake(0, kScreenHeight - 300 - iPhoneXSafeBottomMargin, kScreenWidth, 300 + iPhoneXSafeBottomMargin)];
|
|
|
- MJWeakSelf;
|
|
|
- [_seatActionView opreationCallback:^(LIVESECONTROL action, LiveSeatMember * _Nonnull member) {
|
|
|
- [weakSelf opreationSeatApplyAction:action member:member];
|
|
|
- }];
|
|
|
- _seatActionView.isForbiddenApply = !self.enableSeat;
|
|
|
- }
|
|
|
- return _seatActionView;
|
|
|
-}
|
|
|
-
|
|
|
-- (void)opreationSeatApplyAction:(LIVESECONTROL)control member:(LiveSeatMember *)member {
|
|
|
- switch (control) {
|
|
|
- case LIVESECONTROL_ALLOW: // 允许连麦
|
|
|
- {
|
|
|
- [self sendMicStatusRequest:0];
|
|
|
- }
|
|
|
- break;
|
|
|
- case LIVESECONTROL_FORBIDDEN: // 禁止连麦
|
|
|
- {
|
|
|
- [self sendMicStatusRequest:1];
|
|
|
- }
|
|
|
- break;
|
|
|
- case LIVESECONTROL_APPROVE: // 上麦
|
|
|
- {
|
|
|
- if (member) {
|
|
|
- // 判断连麦人数超过4人 无法点击
|
|
|
- NSInteger count = [self queryConnectingCount];
|
|
|
- if (count >= 4) {
|
|
|
- [LOADING_MANAGER MBShowAUTOHidingInWindow:@"最多支持4人上麦哦~"];
|
|
|
- return;
|
|
|
- }
|
|
|
- KSLiveChatroomSeatResponse *responseMessage = [[KSLiveChatroomSeatResponse alloc] init];
|
|
|
- responseMessage.type = SEATRESPONSE_TEACHERAPPROVE;
|
|
|
- responseMessage.teacherId = self.createrId;
|
|
|
- responseMessage.teacherName = self.createrName;
|
|
|
- responseMessage.audienceId = member.userId;
|
|
|
- responseMessage.audienceName = member.name;
|
|
|
- MJWeakSelf;
|
|
|
- [self sendMessage:responseMessage displayMessage:NO callback:^(BOOL success) {
|
|
|
- [weakSelf refreshSeatArrayRemoveMember:NO member:member];
|
|
|
- }];
|
|
|
- }
|
|
|
- }
|
|
|
- break;
|
|
|
- case LIVESECONTROL_DOWNSEAT: // 下麦
|
|
|
- {
|
|
|
- if (member) {
|
|
|
- KSLiveChatroomSeatApply *kickSeatMessage = [[KSLiveChatroomSeatApply alloc] init];
|
|
|
- kickSeatMessage.type = SEATHANDLE_KICKSEAT;
|
|
|
- kickSeatMessage.teacherId = self.createrId;
|
|
|
- kickSeatMessage.teacherName = self.createrName;
|
|
|
- kickSeatMessage.audienceId = member.userId;
|
|
|
- kickSeatMessage.audienceName = member.name;
|
|
|
-
|
|
|
- MJWeakSelf;
|
|
|
- [self sendMessage:kickSeatMessage displayMessage:NO callback:^(BOOL success) {
|
|
|
- [weakSelf refreshSeatArrayRemoveMember:YES member:member];
|
|
|
- }];
|
|
|
- }
|
|
|
- }
|
|
|
- break;
|
|
|
- case LIVESECONTROL_DOWNSEATALL:
|
|
|
- {
|
|
|
- MJWeakSelf;
|
|
|
- self.alertView = [LiveRoomAlertView liveroomAlertWithTitle:@"确认后所有连麦中学员都将下麦" leftButtonTitle:@"取消" rightTitle:@"确认" inView:self.view cancel:^{
|
|
|
-
|
|
|
- } confirm:^{
|
|
|
- [weakSelf downSeatAll];
|
|
|
- }];
|
|
|
-
|
|
|
- }
|
|
|
- break;
|
|
|
- case LIVESECONTROL_REFUSEALL:
|
|
|
- {
|
|
|
- MJWeakSelf;
|
|
|
- self.alertView = [LiveRoomAlertView liveroomAlertWithTitle:@"确认将正在申请连麦的学员清空?" leftButtonTitle:@"取消" rightTitle:@"确认" inView:self.view cancel:^{
|
|
|
-
|
|
|
- } confirm:^{
|
|
|
- [weakSelf refuseAllSeatApply];
|
|
|
- }];
|
|
|
-
|
|
|
- }
|
|
|
- break;
|
|
|
-
|
|
|
- default:
|
|
|
- break;
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-// 是否允许连麦 0:是 1否
|
|
|
-- (void)sendMicStatusRequest:(NSInteger)whetherMic {
|
|
|
- [LOADING_MANAGER showHUD];
|
|
|
- [KSNetworkingManager liveRoomSetMicApplyEnable:KS_GET roomUid:self.roomId whetherMic:whetherMic success:^(NSDictionary * _Nonnull dic) {
|
|
|
- [LOADING_MANAGER removeHUD];
|
|
|
- if ([dic ks_integerValueForKey:@"code"] == 200 && [dic ks_boolValueForKey:@"status"]) {
|
|
|
- if (whetherMic == 0) {
|
|
|
- self.seatActionView.isForbiddenApply = NO;
|
|
|
- [self enableSeatAction];
|
|
|
- }
|
|
|
- else {
|
|
|
- self.seatActionView.isForbiddenApply = YES;
|
|
|
- [self forceSeatAction];
|
|
|
- }
|
|
|
- }
|
|
|
- else {
|
|
|
- [LOADING_MANAGER MBShowAUTOHidingInWindow:MESSAGEKEY];
|
|
|
- }
|
|
|
- } faliure:^(NSError * _Nonnull error) {
|
|
|
- [LOADING_MANAGER removeHUD];
|
|
|
- }];
|
|
|
-}
|
|
|
-
|
|
|
-- (void)enableSeatAction {
|
|
|
- RCChatroomSeatsControl *message = [[RCChatroomSeatsControl alloc] init];
|
|
|
- message.userId = self.createrId;
|
|
|
- message.userName = self.createrName;
|
|
|
- message.seatBan = NO;
|
|
|
- [self sendMessage:message displayMessage:NO callback:^(BOOL success) {
|
|
|
-
|
|
|
- }];
|
|
|
-}
|
|
|
-
|
|
|
-// 禁止连麦
|
|
|
-- (void)forceSeatAction {
|
|
|
- RCChatroomSeatsControl *message = [[RCChatroomSeatsControl alloc] init];
|
|
|
- message.userId = self.createrId;
|
|
|
- message.userName = self.createrName;
|
|
|
- message.seatBan = YES;
|
|
|
- MJWeakSelf;
|
|
|
- [self sendMessage:message displayMessage:NO callback:^(BOOL success) {
|
|
|
- [weakSelf removeSeatMember:YES];
|
|
|
- }];
|
|
|
-}
|
|
|
-// 全员下麦
|
|
|
-- (void)downSeatAll {
|
|
|
- KSDownSeatAllMessage *message = [[KSDownSeatAllMessage alloc] init];
|
|
|
- MJWeakSelf;
|
|
|
- [self sendMessage:message displayMessage:NO callback:^(BOOL success) {
|
|
|
- [weakSelf removeSeatMember:NO];
|
|
|
- }];
|
|
|
-}
|
|
|
-
|
|
|
-- (void)refuseAllSeatApply {
|
|
|
- KSRejectAllSeatMessage *message = [[KSRejectAllSeatMessage alloc] init];
|
|
|
- MJWeakSelf;
|
|
|
- [self sendMessage:message displayMessage:NO callback:^(BOOL success) {
|
|
|
- [weakSelf removeSeatMember:YES];
|
|
|
- }];
|
|
|
-}
|
|
|
-
|
|
|
-- (void)removeSeatMember:(BOOL)isApply {
|
|
|
- NSMutableArray *seatArray = [self.seatApplyArray mutableCopy];
|
|
|
-
|
|
|
- if (isApply) {
|
|
|
- NSMutableArray *array = [NSMutableArray array];
|
|
|
- for (LiveSeatMember *member in seatArray) {
|
|
|
- if (member.isConnected == YES) {
|
|
|
- [array addObject:member];
|
|
|
- }
|
|
|
- }
|
|
|
- self.seatApplyArray = [NSMutableArray arrayWithArray:array];
|
|
|
- }
|
|
|
- else {
|
|
|
- NSMutableArray *array = [NSMutableArray array];
|
|
|
- for (LiveSeatMember *member in seatArray) {
|
|
|
- if (member.isConnected == NO) {
|
|
|
- [array addObject:member];
|
|
|
- }
|
|
|
- }
|
|
|
- self.seatApplyArray = [NSMutableArray arrayWithArray:array];
|
|
|
- }
|
|
|
- [self refreshSeatApplyView];
|
|
|
-}
|
|
|
-
|
|
|
-- (void)refreshSeatArrayRemoveMember:(BOOL)isRemove member:(LiveSeatMember *)member {
|
|
|
- if (isRemove) {
|
|
|
- [self.seatApplyArray removeObject:member];
|
|
|
- }
|
|
|
- else {
|
|
|
- member.isConnected = YES;
|
|
|
- if (![self judgeContainMember:member.userId]) {
|
|
|
- [self.seatApplyArray addObject:member];
|
|
|
- NSLog(@"hah--------");
|
|
|
- }
|
|
|
- }
|
|
|
- [self refreshSeatApplyView];
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
-- (NSMutableArray *)seatApplyArray {
|
|
|
- if (!_seatApplyArray) {
|
|
|
- _seatApplyArray = [NSMutableArray array];
|
|
|
- }
|
|
|
- return _seatApplyArray;
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
-- (LiveMoreDisplayView *)moreView {
|
|
|
- if (!_moreView) {
|
|
|
- _moreView = [LiveMoreDisplayView shareInstance];
|
|
|
- _moreView.frame = CGRectMake(0, 0, KPortraitWidth, KPortraitHeight);
|
|
|
- MJWeakSelf;
|
|
|
- [_moreView operationQuitAction:^(BOOL isCloseRoom) {
|
|
|
- [weakSelf leaveRoom:isCloseRoom];
|
|
|
- }];
|
|
|
- }
|
|
|
- return _moreView;
|
|
|
-}
|
|
|
-
|
|
|
-- (void)leaveRoom:(BOOL)closeRoom {
|
|
|
- if (closeRoom) {
|
|
|
- [self closeRoomAction];
|
|
|
- }
|
|
|
- else {
|
|
|
- [self pauseAction];
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-- (LiveroomTimeManager *)timeManager {
|
|
|
- if (!_timeManager) {
|
|
|
- _timeManager = [[LiveroomTimeManager alloc] initWithDelegate:self];
|
|
|
- }
|
|
|
- return _timeManager;
|
|
|
-}
|
|
|
-
|
|
|
-- (NSInteger)getCloseTime {
|
|
|
-
|
|
|
- return self.expiredCloseMinute;
|
|
|
-}
|
|
|
-
|
|
|
-- (void)dealloc {
|
|
|
- NSLog(@"------- dealloc --------");
|
|
|
- if (_timeManager) {
|
|
|
- [_timeManager stopDurationTimer];
|
|
|
- }
|
|
|
- [[NSNotificationCenter defaultCenter] removeObserver:self];
|
|
|
- if (_timer) {
|
|
|
- dispatch_source_cancel(_timer);
|
|
|
- _timer = nil;
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-- (dispatch_source_t)timer {
|
|
|
- if (!_timer) {
|
|
|
- _timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0,dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0));
|
|
|
- uint64_t interval = (uint64_t)(10 * NSEC_PER_SEC);
|
|
|
- dispatch_source_set_timer(_timer, DISPATCH_TIME_NOW, interval, 0);
|
|
|
- MJWeakSelf;
|
|
|
- dispatch_source_set_event_handler(_timer, ^{
|
|
|
- dispatch_async(dispatch_get_main_queue(), ^{
|
|
|
- [weakSelf syncLikeCount];
|
|
|
- });
|
|
|
- });
|
|
|
- }
|
|
|
- return _timer;
|
|
|
-}
|
|
|
-
|
|
|
-- (void)showAnimationView:(BOOL)isJoinRoom showMessag:(NSString *)message {
|
|
|
- if (self.animationView && self.animationView.isShow) {
|
|
|
- return;
|
|
|
- }
|
|
|
- else {
|
|
|
- if (self.pageType == LIVEPAGE_PREVIEW) {
|
|
|
- return;
|
|
|
- }
|
|
|
- ANIMATIONTYPE type = isJoinRoom ? ANIMATIONTYPE_JOIN : ANIMATIONTYPE_RUSH;
|
|
|
- self.animationView = [[LiveAnimationView alloc] initWithTitle:message animationType:type];
|
|
|
- [self.view addSubview:self.animationView];
|
|
|
- [self.animationView mas_makeConstraints:^(MASConstraintMaker *make) {
|
|
|
- make.left.right.mas_equalTo(self.view);
|
|
|
- make.width.mas_equalTo(KPortraitWidth);
|
|
|
- make.height.mas_equalTo(24.0f);
|
|
|
- make.bottom.mas_equalTo(self.messageContentView.mas_top).offset(-6);
|
|
|
- }];
|
|
|
- [self.view bringSubviewToFront:self.animationView];
|
|
|
- NSLog(@"------- start animation ");
|
|
|
- MJWeakSelf;
|
|
|
- [self.animationView startAnimationEndCallback:^{
|
|
|
- NSLog(@"----- hide ");
|
|
|
- weakSelf.animationView.isShow = YES;
|
|
|
- weakSelf.animationView = nil;
|
|
|
- }];
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-#pragma mark ---- 同步点赞数据
|
|
|
-
|
|
|
-- (void)syncLikeCount {
|
|
|
- if (self.isOtherLogin) {
|
|
|
- return;
|
|
|
- }
|
|
|
- [KSNetworkingManager syncLikeRequest:KS_GET likeNum:self.likeCount roomUid:self.roomId success:^(NSDictionary * _Nonnull dic) {
|
|
|
- if ([dic ks_integerValueForKey:@"code"] == 200 && [dic ks_boolValueForKey:@"status"]) {
|
|
|
- [self notiferLikeStatusToAudience];
|
|
|
- }
|
|
|
- } faliure:^(NSError * _Nonnull error) {
|
|
|
-
|
|
|
- }];
|
|
|
-}
|
|
|
-
|
|
|
-- (void)notiferLikeStatusToAudience {
|
|
|
- RCChatroomLikeCount *likeCountMsg = [[RCChatroomLikeCount alloc] init];
|
|
|
- likeCountMsg.count = self.likeCount;
|
|
|
-
|
|
|
- [self sendMessage:likeCountMsg displayMessage:NO callback:^(BOOL success) {
|
|
|
-
|
|
|
- }];
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
-/*
|
|
|
-#pragma mark - Navigation
|
|
|
-
|
|
|
-// In a storyboard-based application, you will often want to do a little preparation before navigation
|
|
|
-- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
|
|
|
- // Get the new view controller using [segue destinationViewController].
|
|
|
- // Pass the selected object to the new view controller.
|
|
|
-}
|
|
|
-*/
|
|
|
-
|
|
|
-@end
|