1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839 |
- //
- // TXLiveRoomViewController.m
- // StudentDaya
- //
- // Created by 王智 on 2023/2/21.
- // Copyright © 2023 DayaMusic. All rights reserved.
- //
- #import "TXLiveRoomViewController.h"
- #import "TXLiteAVSDK_Professional/TXLiteAVSDK.h"
- #import "KSLiveEmptyView.h"
- #import "TXLiveVideoView.h"
- #import "LiveRoomHeadView.h"
- #import "LiveRoomBottomView.h"
- #import <Lottie/Lottie.h>
- #import "KSChatInputBarControl.h"
- #import "TXLiveChatListCell.h"
- #import "AppDelegate.h"
- #import <KSToolLibrary/UIDevice+TFDevice.h>
- #import "LiveRoomLikeLayer.h"
- #import "LiveAlertView.h"
- #import "KSShopCardView.h"
- #import "KSLiveWebViewController.h"
- #import "KSLiveBadNetView.h"
- #import "KSLiveEndView.h"
- #import "LiveAnimationView.h"
- #import "LiveApplyView.h"
- #import "LiveApplyingView.h"
- #import <ImSDK_Plus/ImSDK_Plus.h>
- #import "TXIMLinsenter.h"
- #import "TXLiveMessageModel.h"
- #import "TXLiveURLUtils.h"
- #import "TXLiveMessageCenter.h"
- #import "KSDragWindowManager.h"
- #import "TXLiveLoadingView.h"
- #import "TXUISeatMember.h"
- #import "TXSeatContainerView.h"
- #import "LiveRoomConfirmAlert.h"
- #import "LiveModuleService.h"
- #define AUTOHIDE_TIME (10.0f)
- typedef NS_ENUM(NSInteger, MICSTATUS) {
- MICSTATUS_NOMAL, // 正常状态
- MICSTATUS_WAITING, // 申请中
- MICSTATUS_CONNECTING, // 连麦中
- };
- @interface TXLiveRoomViewController ()<UIGestureRecognizerDelegate,KSChatInputBarControlDelegate,UITableViewDataSource,UITableViewDelegate,V2TXLivePlayerObserver,TRTCCloudDelegate>
- // 是否是观众
- @property (nonatomic, assign) BOOL isAudience;
- // rtc 连麦时使用
- @property (nonatomic, strong) TRTCCloud *trtcCloud;
- @property (nonatomic, strong) V2TXLivePlayer *livePlayer;
- @property (nonatomic, strong) LiveRoomHeadView *headView;
- @property (nonatomic, copy) LiveRoomBottomView *bottomView;
- // 视频主窗口容器
- @property (nonatomic, strong) UIView *videoContainerView;
- // 主屏videoView
- @property (nonatomic, strong) UIView *videoView;
- // 画面渲染的画面
- @property (nonatomic, strong) TXLiveVideoView *videoRenderView;
- // 切换按钮
- @property (nonatomic, strong) UIButton *switchButton;
- @property (nonatomic, strong) LOTAnimationView *animationView;
- /// 连麦的视图
- @property (nonatomic, strong) TXSeatContainerView *seatContainer;
- // 聊天UI
- /*!
- 消息列表CollectionView和输入框都在这个view里
- */
- @property(nonatomic, strong) UIView *messageContentView;
- /*!
- 会话页面的TableView
- */
- @property (nonatomic, strong) UITableView *conversationMessageTableView;
- /*!
- 聊天内容的消息Cell数据模型的数据源
-
- @discussion 数据源中存放的元素为消息Cell的数据模型,即RCDLiveMessageModel对象。
- */
- @property(nonatomic, strong) NSMutableArray<TXLiveMessageModel *> *conversationDataRepository;
- /**
- 输入工具栏
- */
- @property(nonatomic,strong) KSChatInputBarControl *inputBar;
- /**
- * 是否需要滚动到底部
- */
- @property(nonatomic, assign) BOOL isNeedScrollToButtom;
- /**
- 上次点赞按钮点击时间
- */
- @property(nonatomic, assign) NSTimeInterval lastClickPraiseTime;
- @property (nonatomic, assign) BOOL landScape;
- @property (nonatomic, assign) BOOL isHiddenHeadView;
- // 连麦状态
- @property (nonatomic, assign) MICSTATUS micStatus;
- @property (nonatomic, strong) LiveApplyView *applyView; // 未申请
-
- @property (nonatomic, strong) LiveApplyingView *applyingView; // 申请中
- @property (nonatomic, assign) BOOL isCreaterVideoEnable;
- @property (nonatomic, assign) BOOL isCloseRoom; // 是否直播结束
- /// 提示窗
- @property (nonatomic, strong) LiveAlertView *alertView;
- @property (nonatomic, strong) KSShopCardView *cardView;
- @property (nonatomic, assign) NSTimeInterval lastSendMsgTime;
- @property (nonatomic, strong) LiveAnimationView *enterAnimationView;
- @property (nonatomic, strong) KSLiveEndView *endView; // 直播结束显示的画面
- @property (nonatomic, strong) KSLiveEmptyView *emptyView;
- @property (nonatomic, strong) KSLiveBadNetView *netBadView;
- /// 是否在切换身份
- @property (nonatomic, assign) BOOL isTransferRole;
- @property (nonatomic, assign) BOOL hasSendWelcomeMessage;
- // 远端连麦用户
- @property (nonatomic, strong) NSMutableArray *remoteMemberArray;
- @property (nonatomic, assign) BOOL isPauseLive;
- @property (nonatomic, strong) TXLiveLoadingView *loadingView;
- @property (nonatomic, assign) BOOL hasShowSuspendView;
- @property (nonatomic, assign) BOOL muteRoomMic;
- @property (nonatomic, assign) BOOL micEnable;
- @property (nonatomic, strong) LiveRoomConfirmAlert *closeAlert;
- @property (nonatomic, assign) BOOL isConnectedFailed;
- #pragma mark --- 时间统计
- // 后端返回进入教室时间戳 ms
- @property (nonatomic, assign) NSTimeInterval enterTime;
- // 进入教室时间date
- @property (nonatomic, strong) NSDate *enterDate;
- @end
- // 用于记录点赞消息连续点击的次数
- static int clickPraiseBtnTimes = 0;
- @implementation TXLiveRoomViewController
- - (instancetype)init {
- self = [super init];
- if (self) {
- [self defaultConfig];
- [self default3AConfig];
- }
- return self;
- }
- - (void)default3AConfig {
- self.ANS = 0;
- self.AEC = 100;
- self.AGC = 0;
- }
- - (void)joinChatRoom {
- if (TXIM_LINSENTER.loginIMSuccess == NO) {
- [TXIM_LINSENTER TXIMLoginWithUserId:UserDefault(IM_USERID) sig:self.UserSig callback:^(BOOL isSuccess, NSString * _Nullable msg) {
- [self liveConversationJoin];
- }];
- }
- else {
- [self liveConversationJoin];
- }
- }
- - (void)liveConversationJoin {
- [[V2TIMManager sharedInstance] joinGroup:self.roomId msg:nil succ:^{
- dispatch_async(dispatch_get_main_queue(), ^{
- [self addConstMessage];
- [self sendWelcomeMessage];
- [self getGroupAttrInfo];
- [self getGroupCount];
- });
-
- } fail:^(int code, NSString *desc) {
- NSLog(@"");
- }];
- }
- - (void)getGroupAttrInfo {
- [[V2TIMManager sharedInstance] getGroupAttributes:self.roomId keys:nil succ:^(NSMutableDictionary<NSString *,NSString *> *groupAttributeList) {
- NSLog(@"");
- [self evaluateGroupInfo:groupAttributeList];
- } fail:^(int code, NSString *desc) {
-
- }];
- }
- - (void)getGroupCount {
- [[V2TIMManager sharedInstance] getGroupCounters:self.roomId keys:nil succ:^(NSDictionary<NSString *,NSNumber *> *groupCounters) {
- NSLog(@"");
- [self evaluateGroupCount:groupCounters];
- } fail:^(int code, NSString *desc) {
-
- }];
- }
- - (void)addConstMessage {
- TXConstMessage *statement = [[TXConstMessage alloc] init];
- statement.userInfo = [self getCurrentUser];
- statement.text = @"欢迎进入直播课堂,请遵守相关法规,禁止传播低俗、暴力等不良信息。为孩子创造健康绿色的学习环境。";
- [self appendAndDisplayMessage:statement];
- }
- - (void)sendWelcomeMessage {
- TXLiveMessageWelcome *welcomeMessage = [[TXLiveMessageWelcome alloc] init];
- welcomeMessage.userInfo = [self getCurrentUser];
- MJWeakSelf;
- [self sendCustomMessage:welcomeMessage priority:V2TIM_PRIORITY_DEFAULT displayMessage:NO callback:^(BOOL success) {
- weakSelf.hasSendWelcomeMessage = YES;
- [weakSelf showEnterMessageAndJoinRoom];
- }];
- }
- - (void)showEnterMessageAndJoinRoom {
- NSString *contentString = [NSString stringWithFormat:@"%@ 进入直播间",UserDefault(NicknameKey)];
- [self showAnimationView:YES showMessag:contentString];
- }
- - (void)joinLiveRoom {
- [self changeEmptyStatusView];
- [self resetNetTips];
- [self startPlay];
- }
- - (void)viewWillAppear:(BOOL)animated {
- [super viewWillAppear:animated];
- [UIApplication sharedApplication].idleTimerDisabled = YES;
- [IQKeyboardManager sharedManager].enableAutoToolbar = NO;
- [IQKeyboardManager sharedManager].enable = NO;
- [UIApplication sharedApplication].statusBarStyle = UIStatusBarStyleLightContent;
- // 重新渲染view
- KSDragWindowManager *manager = [KSDragWindowManager sharedManager];
- if (manager.hasShowWindow) {
- [manager resignDragWindow];
- }
- if (self.hasShowSuspendView) {
- [self.videoView addSubview:self.videoRenderView];
- [self.videoRenderView mas_updateConstraints:^(MASConstraintMaker *make) {
- make.left.right.bottom.top.mas_equalTo(self.videoView);
- }];
- _hasShowSuspendView = NO;
- }
- if (self.bottomView.isMute == NO) {
- [self muteVoiceAction];
- }
- }
- - (void)viewWillDisappear:(BOOL)animated {
- [super viewWillDisappear:animated];
- [UIApplication sharedApplication].idleTimerDisabled = NO;
- if (self.landScape) {
- [self changeOrientation: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)defaultConfig {
- self.enableChat = YES;
- self.enableSeat = YES;
- self.enableLike = YES;
- self.needSwitchButton = NO;
- self.micStatus = MICSTATUS_NOMAL;
- self.isCreateInRoom = NO; // 默认主讲人不在房间
- self.blacklistFlag = NO;
- self.isCloseRoom = NO;
- self.lastClickPraiseTime = 0;
- self.isAudience = YES;
- self.isCreaterVideoEnable = YES;
- }
- - (void)viewDidLoad {
- [super viewDidLoad];
- // Do any additional setup after loading the view.
- self.ks_prefersNavigationBarHidden = YES;
- [self setupUI];
- [self registerNotification];
- [self joinChatRoom];
- [self joinLiveRoom];
- [self notiferJoinSuccessToServiceCallback:^{
- }];
- }
- - (void)registerNotification {
- [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didReceiveMessageNotification:) name:OnReceiveTXLiveMessageNotification object:nil];
-
- [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(liveroomLogOut) name:@"liveroomLogout" object:nil];
-
- [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(liveroomQuit) name:@"liveroomQuit" object:nil];
-
- [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(IMConnetedCallback) name:@"TXIMConnected" object:nil];
- [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(muteAllAudio) name:@"muteLiveAudio" object:nil];
-
- [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didReceiveGroupMessage:) name:OnReceiveTXLiveGroupNotification object:nil];
- [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didReceiveGroupCountMessage:) name:OnReceiveTXLiveGroupCountNotification object:nil];
- [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(networkTips) name:@"networkError" object:nil];
- }
- - (void)networkTips {
- [LOADING_MANAGER MBShowAUTOHidingInWindow:@"直播已断开,请检查您的网络"];
- self.isConnectedFailed = YES;
- }
- - (void)IMConnetedCallback {
- self.isConnectedFailed = NO;
- dispatch_main_async_safe(^{
- // IM 连接成功回调
- if (self.hasSendWelcomeMessage) { // 如果已经发送了进入消息
- // 查询是否直播间开启
- [LiveModuleService imLiveBroadcastRoomQueryRoomRequest:KS_GET roomId:self.roomId success:^(NSDictionary * _Nonnull dic) {
- if ([dic ks_integerValueForKey:@"code"] == 200 && [dic ks_boolValueForKey:@"status"]) {
- // 回调信息
- MJWeakSelf;
- [self notiferJoinSuccessToServiceCallback:^{
- [weakSelf sendWelcomeMessage];
- [weakSelf checkPlayerStatus];
- }];
- }
- else {
- [LOADING_MANAGER MBShowAUTOHidingInWindow:MESSAGEKEY];
- [self quitRoom];
- }
- } faliure:^(NSError * _Nonnull error) {
-
- }];
-
- // 查询群属性
- [self getGroupAttrInfo];
- }
- });
- }
-
- - (void)checkPlayerStatus {
- if (self.isCloseRoom) {
- return;
- }
- if (self.isAudience) {
- if (self.livePlayer.isPlaying == NO) {
- [self resetNetTips];
- [self startPlay];
- }
- }
- else {
- [self connectHostWithStatus:NO];
- }
- }
- - (void)liveroomLogOut {
- [LOADING_MANAGER MBShowAUTOHidingInWindow:@"该账号在其他设备上登录"];
- [self quitRoom];
- dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.5f * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
- [[NSNotificationCenter defaultCenter] postNotificationName:@"backLoginView" object:nil];
- });
- }
- - (void)liveroomQuit {
- [self quitRoom];
- dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.5f * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
- [[NSNotificationCenter defaultCenter] postNotificationName:@"backLoginView" object:nil];
- });
- }
- - (void)muteAllAudio {
- [self muteVoiceAction];
- }
- #pragma mark ----- // 观众上下麦
- - (void)connectHostWithStatus:(BOOL)isConnect {
- // 如果直播结束 不转换身份
- if (self.isCloseRoom == YES) {
- return;
- }
- // 转换中,不再处理转换身份
- if (self.isTransferRole) {
- return;
- }
- if (isConnect && self.isAudience == NO) {
- self.micStatus = MICSTATUS_CONNECTING;
- return;
- }
- else if (isConnect == NO && self.isAudience) {
- self.micStatus = MICSTATUS_NOMAL;
- return;
- }
- self.isTransferRole = YES;
- self.micEnable = YES;
- // 清理当前视图
- [self removeSeatContainer];
- self.remoteMemberArray = [NSMutableArray array];
- // 移除状态视图
-
- if (isConnect) {
- [self stopPlay];
- [self hideTipsView];
- if (self.isCreaterVideoEnable) {
- [self hideEmptyView];
- }
- self.isAudience = NO;
- [self enterLiveRTCRoom];
- self.isTransferRole = NO;
- self.micStatus = MICSTATUS_CONNECTING;
- }
- else {
- self.isAudience = YES;
- if (self.isPauseLive == NO) {
- [self startPlay];
- }
- if (_trtcCloud) {
- [self.trtcCloud stopAllRemoteView];
- [self.trtcCloud stopLocalAudio];
- [self.trtcCloud exitRoom];
- _trtcCloud = nil;
- [TRTCCloud destroySharedInstance];
- }
- self.micStatus = MICSTATUS_NOMAL;
- self.isTransferRole = NO;
- }
- [self muteVoiceAction];
- }
- - (void)setupUI {
- self.view.backgroundColor = HexRGB(0x25292e);
- [self.view addSubview:self.emptyView];
- [self.view addSubview:self.endView];
-
- [self.view addSubview:self.videoContainerView];
- [self.videoContainerView mas_makeConstraints:^(MASConstraintMaker *make) {
- make.left.right.top.bottom.mas_equalTo(self.view);
- }];
- [self.videoContainerView addSubview:self.videoView];
-
- // 异常的view
- [self.videoContainerView addSubview:self.netBadView];
- // 按钮和视频的布局
- if (self.needSwitchButton) {
- [self.videoView mas_makeConstraints:^(MASConstraintMaker *make) {
- make.left.right.mas_equalTo(self.videoContainerView);
- if (@available(iOS 11.0, *)) {
- make.top.mas_equalTo(self.videoContainerView.mas_safeAreaLayoutGuideTop).offset(160);
- } else {
- // Fallback on earlier versions
- make.top.mas_equalTo(self.videoContainerView.mas_top).offset(160);
- }
- CGFloat rate = 9 / 16.0f;
- make.height.mas_equalTo(self.videoContainerView.mas_width).multipliedBy(rate);
- make.width.height.mas_equalTo(self.videoContainerView).priorityLow();
- make.width.height.lessThanOrEqualTo(self.videoContainerView);
- }];
- // 显示切换按钮
- [self.videoContainerView addSubview:self.switchButton];
- [self.switchButton mas_makeConstraints:^(MASConstraintMaker *make) {
- make.right.mas_equalTo(self.videoContainerView.mas_right).offset(-10);
- make.width.height.mas_equalTo(33);
- make.bottom.mas_equalTo(self.videoView.mas_bottom).offset(-10);
- }];
- self.switchButton.hidden = NO;
-
- }
- else {
- [self.videoView mas_makeConstraints:^(MASConstraintMaker *make) {
- make.left.top.bottom.right.mas_equalTo(self.videoContainerView);
- }];
- }
- // 添加视频预览图
- [self.videoView addSubview:self.videoRenderView];
- [self.videoRenderView mas_makeConstraints:^(MASConstraintMaker *make) {
- make.left.right.top.bottom.mas_equalTo(self.videoView);
- }];
-
- [self.emptyView mas_makeConstraints:^(MASConstraintMaker *make) {
- make.left.right.top.bottom.mas_equalTo(self.videoView);
- }];
- self.emptyView.hidden = YES;
-
- // 直播结束的画面
- [self.endView mas_makeConstraints:^(MASConstraintMaker *make) {
- make.left.right.top.bottom.mas_equalTo(self.videoView);
- }];
- self.endView.hidden = YES;
-
- [self.netBadView mas_makeConstraints:^(MASConstraintMaker *make) {
- make.left.right.top.bottom.mas_equalTo(self.videoView);
- }];
- self.netBadView.hidden = YES;
-
- [self.videoContainerView addSubview:self.headView];
- 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 countMemberCount];
- [self.headView mas_makeConstraints:^(MASConstraintMaker *make) {
- make.left.right.mas_equalTo(self.videoContainerView);
- make.height.mas_equalTo(80);
- if (@available(iOS 11.0, *)) {
- make.top.mas_equalTo(self.videoContainerView.mas_safeAreaLayoutGuideTop).offset(0);
- } else {
- // Fallback on earlier versions
- make.top.mas_equalTo(self.videoContainerView.mas_top).offset(0);
- }
- }];
- // 聊天区域
- [self.videoContainerView addSubview:self.messageContentView];
-
- if (self.hideCartButton == NO) {
- [self.videoContainerView addSubview:self.animationView];
- [self.animationView mas_makeConstraints:^(MASConstraintMaker *make) {
- if (@available(iOS 11.0, *)) {
- make.bottom.mas_equalTo(self.videoContainerView.mas_safeAreaLayoutGuideBottom).offset(-9);
- } else {
- // Fallback on earlier versions
- make.bottom.mas_equalTo(self.videoContainerView.mas_bottom).offset(-9);
- }
- make.centerX.mas_equalTo(self.videoContainerView.mas_right).offset(-80);
- make.width.mas_equalTo(48);
- make.height.mas_equalTo(56);
- }];
- [self.animationView play];
- }
- [self.videoContainerView addSubview:self.bottomView];
- self.bottomView.hideCartVButton = self.hideCartButton;
- [self.bottomView mas_makeConstraints:^(MASConstraintMaker *make) {
- make.left.right.mas_equalTo(self.videoContainerView);
- if (@available(iOS 11.0, *)) {
- make.bottom.mas_equalTo(self.videoContainerView.mas_safeAreaLayoutGuideBottom).offset(-5);
- } else {
- // Fallback on earlier versions
- make.bottom.mas_equalTo(self.videoContainerView.mas_bottom).offset(-5);
- }
- make.height.mas_equalTo(44);
- }];
-
- // 聊天页面
- if (self.needSwitchButton) {
- [self.messageContentView mas_makeConstraints:^(MASConstraintMaker *make) {
- make.left.mas_equalTo(self.videoContainerView.mas_left);
- make.right.mas_equalTo(self.videoContainerView.mas_right);
- make.bottom.mas_equalTo(self.bottomView.mas_top).offset(-5);
- make.top.mas_equalTo(self.videoView.mas_bottom).offset(10).priorityLow();
- }];
- }
- else {
- [self.messageContentView mas_makeConstraints:^(MASConstraintMaker *make) {
- make.left.mas_equalTo(self.videoContainerView.mas_left);
- make.right.mas_equalTo(self.videoContainerView.mas_right);
- make.bottom.mas_equalTo(self.bottomView.mas_top).offset(-10);
- make.height.mas_equalTo(180);
- }];
- }
-
- [self.videoContainerView addSubview:self.inputBar];
- [_inputBar setBackgroundColor: [UIColor whiteColor]];
-
- [_inputBar setFrame:CGRectMake(0, KPortraitHeight, KPortraitWidth , 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);
- }];
-
- UITapGestureRecognizer *resetBottomTapGesture =[[UITapGestureRecognizer alloc]
- initWithTarget:self
- action:@selector(resetBottomGesture:)];
- resetBottomTapGesture.delegate = self;
- [self.videoContainerView addGestureRecognizer:resetBottomTapGesture];
-
- UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(headViewAnimation:)];
- tapGesture.delegate = self;
- [self.videoView addGestureRecognizer:tapGesture];
- }
- - (void)headViewAnimation:(UIGestureRecognizer *)gestureRecognizer {
- if (gestureRecognizer.state == UIGestureRecognizerStateEnded) {
- [self setDefaultBottomViewStatus];
- }
- if (self.landScape) {
- self.isHiddenHeadView = !self.isHiddenHeadView;
- }
- }
- #pragma mark -- 加入直播间和退出直播间回到服务
- - (void)notiferJoinSuccessToServiceCallback:(void(^)(void))callback {
- [LiveModuleService LiveroomJoinRequest:KS_GET roomId:self.roomId success:^(NSDictionary * _Nonnull dic) {
-
- NSTimeInterval enterTime = [dic ks_integerValueForKey:@"data"];
- self.enterTime = enterTime;
- NSDate *currentDate = [NSDate date];
- self.enterDate = currentDate;
- callback();
- } faliure:^(NSError * _Nonnull error) {
- callback();
- }];
- }
- - (void)quitNotiferService {
- NSDate *currentDate = [NSDate date];
- NSTimeInterval timeInterval = [currentDate timeIntervalSinceDate:self.enterDate];
- NSInteger time = (NSInteger)(timeInterval *1000);
- if (self.enterTime > 0) {
- time = self.enterTime + time;
- }
- else {
- time = (NSInteger)([currentDate timeIntervalSince1970] *1000);
- }
-
- [LiveModuleService LiveroomQuit:KS_POST time:time success:^(NSDictionary * _Nonnull dic) {
- if ([dic ks_integerValueForKey:@"errCode"] == 0) {
- NSLog(@"success");
- }
- else {
- NSLog(@"----- error %@", [dic ks_stringValueForKey:@"errMsg"]);
- }
- } faliure:^(NSError * _Nonnull error) {
-
- }];
- }
- #pragma mark ------ 播放控制
- - (void)startPlay {
- if ([self.livePlayer isPlaying] == NO) {
- [self resetNetTips];
- if (self.isCreaterVideoEnable) {
- [self hideEmptyView];
- }
- [self showLoading];
- self.videoRenderView.hasMainStream = YES;
- self.videoRenderView.hasSubStream = NO;
- [self.livePlayer setRenderView:self.videoRenderView.mainView];
- if (self.needSwitchButton) {
- [self.livePlayer setRenderFillMode:V2TXLiveFillModeFit];
- }
- else {
- [self.livePlayer setRenderFillMode:V2TXLiveFillModeFill];
- }
- // 获取url的方法
- NSString *streamId = [NSString stringWithFormat:@"%@_%@", self.roomId, self.createrId];
- NSString *url = [TXLiveURLUtils generateRtmpPlayUrl:streamId playDomain:self.playDomain liveUrlKey:self.liveUrlKey];
- [self.livePlayer startLivePlay:url];
- [self muteVoiceAction];
- }
- }
- - (void)stopPlay {
- if (_livePlayer) {
- if ([self.livePlayer isPlaying]) {
- [self hideLoading];
- [self.livePlayer stopPlay];
- }
- }
- }
- // 不播放声音
- - (void)pauserAudio {
- [self.livePlayer pauseAudio];
- }
- // 恢复声音
- - (void)resumeAudio {
- [self.livePlayer resumeAudio];
- }
- #pragma mark ---- V2TXLivePlayerObserver
- - (void)onError:(id<V2TXLivePlayer>)player code:(V2TXLiveCode)code message:(NSString *)msg extraInfo:(NSDictionary *)extraInfo {
- if (code == V2TXLIVE_ERROR_DISCONNECTED) {
- // 连接断开
- if (self.isPauseLive == NO && self.isCreateInRoom) {
- [self hideLoading];
- [self showBadNetTips];
- }
- }
- else if (code == V2TXLIVE_WARNING_VIDEO_BLOCK) {
-
- }
- NSLog(@"---- V2TXLivePlayer %zd message:%@", code, msg);
- }
- - (void)onConnected:(id<V2TXLivePlayer>)player extraInfo:(NSDictionary *)extraInfo {
- NSLog(@" ------ connected %@", extraInfo);
- self.isPauseLive = NO;
- self.isCreateInRoom = YES;
- if (self.isCreaterVideoEnable) {
- [self hideEmptyView];
- }
- }
- - (void)onVideoPlaying:(id<V2TXLivePlayer>)player firstPlay:(BOOL)firstPlay extraInfo:(NSDictionary *)extraInfo {
- NSLog(@" ------ onVideoPlaying %@", extraInfo);
- [self hideLoading];
- }
- - (void)onVideoResolutionChanged:(id<V2TXLivePlayer>)player width:(NSInteger)width height:(NSInteger)height {
- NSLog(@" ------ onVideoResolutionChanged %zd %zd", width, height);
- }
- // 直播状态
- - (void)onStatisticsUpdate:(id<V2TXLivePlayer>)player statistics:(V2TXLivePlayerStatistics *)statistics {
- NSLog(@"----- V2TXLivePlayerStatistics desc %@", statistics.description);
- }
- - (void)onReceiveSeiMessage:(id<V2TXLivePlayer>)player payloadType:(int)payloadType data:(NSData *)data {
- NSLog(@"----- onReceiveSeiMessage desc %@", [data mj_JSONObject]);
- if (self.isAudience == YES && self.isPauseLive == NO) {
- NSDictionary *parm = [data mj_JSONObject];
- if ([[parm ks_stringValueForKey:@"api"] isEqualToString:@"sync"]) { // 同步连麦人数
- NSArray *memberArray = [parm ks_arrayValueForKey:@"seatUser"];
- NSMutableArray *remoteSeatArray = [NSMutableArray arrayWithArray:memberArray];
- // 移除自己
- NSMutableArray *seatArray = [NSMutableArray array];
- for (NSDictionary *userParm in remoteSeatArray) {
- if (![[userParm ks_stringValueForKey:@"userId"] isEqualToString:UserDefault(IM_USERID)]) {
- TXUISeatMember *member = [[TXUISeatMember alloc] init];
- member.userId = [userParm ks_stringValueForKey:@"userId"];
- member.muteMic = [userParm ks_boolValueForKey:@"micStatus"];
- [seatArray addObject:member];
- }
- }
-
- [self refreshSeatWithMember:seatArray];
- // if (self.remoteMemberArray.count != seatArray.count) { // 如果连麦人数不同
- // [self refreshSeatWithMember:seatArray];
- // }
- // else {
- // BOOL isSameUser = YES;
- // NSMutableArray *seatMemberArr = [self.remoteMemberArray mutableCopy];
- //
- // for (TXUISeatMember *member in seatMemberArr) {
- //
- // if (![remoteSeatArray containsObject:member]) {
- // isSameUser = NO;
- // }
- // }
- // if (isSameUser == NO) {
- // [self refreshSeatWithMember:seatArray];
- // }
- // }
- }
- }
- else {
- [self refreshSeatWithMember:@[]];
- }
- }
- - (void)refreshSeatWithMember:(NSArray *)memberArray {
- self.remoteMemberArray = [NSMutableArray arrayWithArray:memberArray];
- [self renderSeatView];
- }
- #pragma mark --- trtcCloud delegate
- // 远端主播加入房间
- - (void)onRemoteUserEnterRoom:(NSString *)userId {
- if (![self judgeContainerRemoteUser:userId] && ![userId isEqualToString:self.createrId]) { // 如果不包含当前用户 添加 和刷新连麦
- TXUISeatMember *member = [[TXUISeatMember alloc] init];
- member.userId = userId;
- member.muteMic = YES;
- [self.remoteMemberArray addObject:member];
- }
-
- [self renderSeatView];
- }
- // 远端主播离开
- - (void)onRemoteUserLeaveRoom:(NSString *)userId reason:(NSInteger)reason {
- if ([self judgeContainerRemoteUser:userId]) { // 如果包含当前用户 移除当前用和刷新连麦
- [self removeMemberUserId:userId];
- }
- [self renderSeatView];
- }
- - (BOOL)judgeContainerRemoteUser:(NSString *)userId {
- BOOL containUser = NO;
- NSMutableArray *remoteMemArray = [self.remoteMemberArray mutableCopy];
- for (TXUISeatMember *member in remoteMemArray) {
- if ([member.userId isEqualToString:userId]) {
- containUser = YES;
- }
- }
- return containUser;
- }
- - (void)removeMemberUserId:(NSString *)userId {
- NSMutableArray *remoteMemArray = [self.remoteMemberArray mutableCopy];
- for (TXUISeatMember *member in remoteMemArray) {
- if ([member.userId isEqualToString:userId]) {
- [self.remoteMemberArray removeObject:member];
- return;
- }
- }
- }
- - (void)onWarning:(TXLiteAVWarning)warningCode warningMsg:(NSString *)warningMsg extInfo:(NSDictionary *)extInfo {
- NSLog(@" warningMsg %@ extInfo:%@", warningMsg, extInfo.description);
- }
- // 远端视频
- - (void)onUserVideoAvailable:(NSString *)userId available:(BOOL)available {
- NSLog(@"creater remote videoStream status: %d", available);
- if (available) {
- self.videoRenderView.hasMainStream = YES;
- if (self.videoRenderView.hasSubStream) {
- [self.trtcCloud startRemoteView:self.createrId streamType:TRTCVideoStreamTypeBig view:self.videoRenderView.smallView];
- [self.trtcCloud startRemoteView:self.createrId streamType:TRTCVideoStreamTypeSub view:self.videoRenderView.mainView];
- }
- else {
- [self.trtcCloud stopRemoteView:self.createrId streamType:TRTCVideoStreamTypeSub];
- [self.trtcCloud startRemoteView:self.createrId streamType:TRTCVideoStreamTypeBig view:self.videoRenderView.mainView];
- }
- }
- else {
- self.videoRenderView.hasMainStream = NO;
- [self.trtcCloud stopRemoteView:self.createrId streamType:TRTCVideoStreamTypeBig];
- }
- }
- - (void)onUserSubStreamAvailable:(NSString *)userId available:(BOOL)available {
- NSLog(@"creater remote subStream status: %d", available);
- if (available) {
- self.videoRenderView.hasSubStream = YES;
- [self.trtcCloud startRemoteView:self.createrId streamType:TRTCVideoStreamTypeSub view:self.videoRenderView.mainView];
- if (self.videoRenderView.hasMainStream) {
- [self.trtcCloud startRemoteView:self.createrId streamType:TRTCVideoStreamTypeBig view:self.videoRenderView.smallView];
- }
- }
- else {
- self.videoRenderView.hasSubStream = NO;
- [self.trtcCloud stopRemoteView:self.createrId streamType:TRTCVideoStreamTypeSub];
- if (self.videoRenderView.hasMainStream) {
- [self.trtcCloud startRemoteView:self.createrId streamType:TRTCVideoStreamTypeBig view:self.videoRenderView.mainView];
- }
- }
- }
- - (void)onFirstVideoFrame:(NSString *)userId streamType:(TRTCVideoStreamType)streamType width:(int)width height:(int)height {
-
- }
- - (void)onRecvSEIMsg:(NSString *)userId message:(NSData *)message {
- // NSDictionary *parm = [message mj_JSONObject];
- }
- - (void)onUserAudioAvailable:(NSString *)userId available:(BOOL)available {
- for (TXUISeatMember *member in self.remoteMemberArray) {
- if ([member.userId isEqualToString:userId]) {
- member.muteMic = !available;
- }
- }
- [self renderSeatView];
- }
- #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 --- setter
- - (void)setIsHiddenHeadView:(BOOL)isHiddenHeadView {
- if (_isHiddenHeadView == isHiddenHeadView) {
- return;
- }
- _isHiddenHeadView = isHiddenHeadView;
- //告知需要更改约束
- [self.view setNeedsUpdateConstraints];
- [UIView animateWithDuration:0.5 animations:^{
- if (isHiddenHeadView) {
-
- [self.headView mas_updateConstraints:^(MASConstraintMaker *make) {
- if (@available(iOS 11.0, *)) {
- make.top.mas_equalTo(self.videoContainerView.mas_safeAreaLayoutGuideTop).offset(-80);
- } else {
- // Fallback on earlier versions
- make.top.mas_equalTo(self.videoContainerView.mas_top).offset(-80);
- }
- }];
- }
- else {
- [self.headView mas_updateConstraints:^(MASConstraintMaker *make) {
- if (@available(iOS 11.0, *)) {
- make.top.mas_equalTo(self.videoContainerView.mas_safeAreaLayoutGuideTop).offset(10);
- } else {
- // Fallback on earlier versions
- make.top.mas_equalTo(self.videoContainerView.mas_top).offset(10);
- }
- }];
- }
- [self.headView.superview layoutIfNeeded];
- }];
- }
- #pragma mark ----- landscape action
- - (void)transferToLandscape {
- [self setDefaultBottomViewStatus];
- [self changeOrientation:!self.landScape];
- }
- - (void)changeOrientation:(BOOL)isLandScape {
- self.landScape = isLandScape;
- if (isLandScape) {
- if (IS_IPAD) {
- self.zh_statusBarHidden = YES;
- }
- // 切换到横屏
- AppDelegate* delegate = (AppDelegate*)[UIApplication sharedApplication].delegate;
- delegate.allowAutoRotate = YES;
- [UIDevice switchNewOrientation:UIInterfaceOrientationLandscapeRight inController:self];
- }
- else {
- if (IS_IPAD) {
- self.zh_statusBarHidden = NO;
- }
- AppDelegate* delegate = (AppDelegate*)[UIApplication sharedApplication].delegate;
- delegate.allowAutoRotate = NO;
- [UIDevice switchNewOrientation:UIInterfaceOrientationPortrait inController:self];
- }
- self.isHiddenHeadView = NO;
- [self updateConstraint];
- }
- - (void)updateConstraint {
- if (self.landScape) {
- self.bottomView.hideChatView = YES;
- self.messageContentView.hidden = YES;
- self.headView.hideQuitButton = YES;
- [self.videoView mas_remakeConstraints:^(MASConstraintMaker *make) {
- if (IS_IPAD) {
- make.left.right.mas_equalTo(self.videoContainerView);
- make.centerX.mas_equalTo(self.videoContainerView.mas_centerX);
- CGFloat rate = 9 / 16.0f;
- make.height.mas_equalTo(self.videoContainerView.mas_width).multipliedBy(rate);
- make.width.height.mas_equalTo(self.videoContainerView).priorityLow();
- make.width.height.lessThanOrEqualTo(self.videoContainerView);
- }
- else {
- make.top.bottom.mas_equalTo(self.videoContainerView);
- make.centerX.mas_equalTo(self.videoContainerView.mas_centerX);
- // 宽高设置
- CGFloat rate = 16 / 9.0f;
- make.width.mas_equalTo(self.videoContainerView.mas_height).multipliedBy(rate);
- make.width.height.mas_equalTo(self.videoContainerView).priorityLow();
- make.width.height.lessThanOrEqualTo(self.videoContainerView);
- }
-
- }];
- [self.switchButton mas_remakeConstraints:^(MASConstraintMaker *make) {
- make.right.mas_equalTo(self.videoContainerView.mas_right).offset(-10);
- make.width.height.mas_equalTo(33);
- make.centerY.mas_equalTo(self.videoView.mas_centerY);
- }];
-
- }
- else {
- self.bottomView.hideChatView = NO;
- self.messageContentView.hidden = NO;
- self.headView.hideQuitButton = NO;
- [self.videoView mas_remakeConstraints:^(MASConstraintMaker *make) {
- make.left.right.mas_equalTo(self.videoContainerView);
- if (@available(iOS 11.0, *)) {
- make.top.mas_equalTo(self.videoContainerView.mas_safeAreaLayoutGuideTop).offset(160);
- } else {
- // Fallback on earlier versions
- make.top.mas_equalTo(self.videoContainerView.mas_top).offset(160);
- }
- CGFloat rate = 9 / 16.0f;
- make.height.mas_equalTo(self.videoContainerView.mas_width).multipliedBy(rate);
- make.width.height.mas_equalTo(self.videoContainerView).priorityLow();
- make.width.height.lessThanOrEqualTo(self.videoContainerView);
- }];
- [self.switchButton mas_remakeConstraints:^(MASConstraintMaker *make) {
- make.right.mas_equalTo(self.videoContainerView.mas_right).offset(-10);
- make.width.height.mas_equalTo(33);
- make.bottom.mas_equalTo(self.videoView.mas_bottom).offset(-10);
- }];
- }
-
- // 更新连麦UI
- if ([self.videoContainerView.subviews containsObject:self.seatContainer]) {
- [self updateSeatContainerConstraint];
- }
- }
- - (void)showEmptyViewDisplay:(BOOL)isPublish {
- NSString *imageName = @"";
- NSString *descMessage = @"";
- if (isPublish) {
- imageName = @"liveVideo_close";
- descMessage = @"主讲人已关闭画面!";
- }
- else {
- imageName = @"liveroom_empty";
- descMessage = @"休息一下,马上回来!";
- }
- [self.emptyView configViewWithImageName:imageName desc:descMessage];
- [self hideTipsView];
- self.videoView.hidden = YES;
- self.emptyView.hidden = NO;
- }
- - (void)hideEmptyView {
- self.emptyView.hidden = YES;
- self.videoView.hidden = NO;
- }
- - (void)changeEmptyStatusView {
- if (self.isCloseRoom == NO) { // 只有在非结束直播状态下
- if (self.isPauseLive) { // 暂停直播
- [self showEmptyViewDisplay:NO];
- }
- else { // 如果未暂停直播
- if (self.isCreaterVideoEnable) { // 如果摄像头开启
- [self hideTipsView];
- [self hideEmptyView];
- }
- else { // 主播关闭了摄像头
- [self showEmptyViewDisplay:YES];
- }
- }
-
- }
- }
- - (void)renderSeatView {
-
- NSMutableArray *seatArray = [NSMutableArray array];
- NSArray *remoteUserArray = [self.remoteMemberArray mutableCopy];
- for (TXUISeatMember *member in remoteUserArray) {
- [seatArray addObject:member];
- }
-
- BOOL isContainSelf = NO;
- for (TXUISeatMember *member in seatArray) {
- if ([member.userId isEqualToString:UserDefault(IM_USERID)]) {
- isContainSelf = YES;
- break;
- }
- }
- if (self.micStatus == MICSTATUS_CONNECTING && !isContainSelf) {
- TXUISeatMember *currentMember = [[TXUISeatMember alloc] init];
- currentMember.userId = UserDefault(IM_USERID);
- currentMember.muteMic = !self.micEnable;
- [seatArray addObject:currentMember];
- }
- NSLog(@"-- seat member--- %zd -", seatArray.count);
- if (seatArray.count) {
- if (![self.videoContainerView.subviews containsObject:self.seatContainer]) {
- [self.videoContainerView addSubview:self.seatContainer];
- }
- [self updateSeatContainerConstraint];
-
- // self.seatContainer.seatMemberArray = [NSMutableArray arrayWithArray:seatArray];
- // [self.seatContainer refreshSeatUI];
- [self.seatContainer refreshSeatUIWithMember:[NSMutableArray arrayWithArray:seatArray]];
- }
- else {
- [self removeSeatContainer];
- }
- }
- // 移除连麦视图
- - (void)removeSeatContainer {
- if ([self.videoContainerView.subviews containsObject:self.seatContainer]) {
- [self.seatContainer removeFromSuperview];
- }
- }
- - (void)updateSeatContainerConstraint {
- if (self.landScape) {
- [self.seatContainer mas_remakeConstraints:^(MASConstraintMaker *make) {
- if (@available(iOS 11.0, *)) {
- make.left.mas_equalTo(self.videoContainerView.mas_safeAreaLayoutGuideLeft);
- } else {
- // Fallback on earlier versions
- make.left.mas_equalTo(self.videoContainerView.mas_left);
- }
- make.right.mas_equalTo(self.videoContainerView.mas_right).offset(-70);
- if (@available(iOS 11.0, *)) {
- make.top.mas_equalTo(self.videoContainerView.mas_safeAreaLayoutGuideTop).offset(85);
- } else {
- // Fallback on earlier versions
- make.top.mas_equalTo(self.videoContainerView.mas_top).offset(85);
- }
- make.height.mas_equalTo(70);
- }];
- }
- else {
- [self.seatContainer mas_remakeConstraints:^(MASConstraintMaker *make) {
- make.left.right.mas_equalTo(self.videoContainerView);
- make.top.mas_equalTo(self.headView.mas_bottom).offset(0);
- make.height.mas_equalTo(70);
- }];
- }
- }
- #pragma mark ----- 加入TRC房间
- - (void)enterLiveRTCRoom {
- self.videoRenderView.hasMainStream = NO;
- self.videoRenderView.hasSubStream = NO;
- TRTCParams *parms = [[TRTCParams alloc] init];
- parms.sdkAppId = CONFIG_TXSDKAPPID;
- parms.userSig = self.UserSig;
- parms.role = TRTCRoleAnchor;
- parms.strRoomId = self.roomId;
- parms.userId = UserDefault(IM_USERID);
- [self.trtcCloud addDelegate:self];
- [self config3AParams];
- [self configVideoAndAudioSetting];
- [self.trtcCloud enterRoom:parms appScene:TRTCAppSceneLIVE];
- TRTCRenderParams *rendParams = [[TRTCRenderParams alloc] init];
-
- if (self.needSwitchButton) {
- rendParams.fillMode = TRTCVideoFillMode_Fit;
- }
- else {
- rendParams.fillMode = TRTCVideoFillMode_Fill;
- }
- [self.trtcCloud setRemoteRenderParams:self.createrId streamType:TRTCVideoStreamTypeBig params:rendParams];
- [self.trtcCloud setRemoteRenderParams:self.createrId streamType:TRTCVideoStreamTypeSub params:rendParams];
- }
- - (void)configVideoAndAudioSetting {
- [self.trtcCloud startLocalAudio:TRTCAudioQualityMusic];
- TRTCVideoEncParam *videoEncParam = [[TRTCVideoEncParam alloc] init];
- videoEncParam.videoFps = 24;
- videoEncParam.resMode = TRTCVideoResolutionModePortrait;
- videoEncParam.videoResolution = TRTCVideoResolution_960_540;
- [self.trtcCloud setVideoEncoderParam:videoEncParam];
-
- if (self.muteRoomMic) {
- [self micButtonAction:self.muteRoomMic];
- }
- }
- // 配置3A参数
- - (void)config3AParams {
- [self configANSParm:self.ANS];
- [self configAECParm:self.AEC];
- [self configAGCParm:self.AGC];
- }
- // 背景音抑制
- - (void)configANSParm:(NSInteger)number {
- NSMutableDictionary *dic = [NSMutableDictionary dictionary];
- [dic setValue:@"enableAudioANS" forKey:@"api"];
- NSMutableDictionary *subDic = [NSMutableDictionary dictionary];
- if (number > 0) {
- [subDic setValue:@(1) forKey:@"enable"];
- [subDic setValue:@(number) forKey:@"level"];
- }
- else {
- [subDic setValue:@(0) forKey:@"enable"];
- [subDic setValue:@(0) forKey:@"level"];
- }
- [dic setValue:subDic forKey:@"params"];
- NSData *data = [NSJSONSerialization dataWithJSONObject:dic options:kNilOptions error:nil];
- NSString *jsonString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
- [self.trtcCloud callExperimentalAPI:jsonString];
- }
- // 回声消除
- - (void)configAECParm:(NSInteger)number {
- NSMutableDictionary *dic = [NSMutableDictionary dictionary];
- [dic setValue:@"enableAudioAEC" forKey:@"api"];
- NSMutableDictionary *subDic = [NSMutableDictionary dictionary];
- if (number > 0) {
- [subDic setValue:@(1) forKey:@"enable"];
- [subDic setValue:@(number) forKey:@"level"];
- }
- else {
- [subDic setValue:@(0) forKey:@"enable"];
- [subDic setValue:@(0) forKey:@"level"];
- }
- [dic setValue:subDic forKey:@"params"];
- NSData *data = [NSJSONSerialization dataWithJSONObject:dic options:kNilOptions error:nil];
- NSString *jsonString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
- [self.trtcCloud callExperimentalAPI:jsonString];
- }
- // 自动增益
- - (void)configAGCParm:(NSInteger)number {
- NSMutableDictionary *dic = [NSMutableDictionary dictionary];
- [dic setValue:@"enableAudioAGC" forKey:@"api"];
- NSMutableDictionary *subDic = [NSMutableDictionary dictionary];
- if (number > 0) {
- [subDic setValue:@(1) forKey:@"enable"];
- [subDic setValue:@(number) forKey:@"level"];
- }
- else {
- [subDic setValue:@(0) forKey:@"enable"];
- [subDic setValue:@(0) forKey:@"level"];
- }
- [dic setValue:subDic forKey:@"params"];
- NSData *data = [NSJSONSerialization dataWithJSONObject:dic options:kNilOptions error:nil];
- NSString *jsonString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
- [self.trtcCloud callExperimentalAPI:jsonString];
- }
- #pragma mark -------- live message handle
- - (NSString *)getMsgClassName:(NSString *)messageObjectName {
- TXLiveMessageModel *configModel = [[TXLiveMessageModel alloc] init];
- NSString *className = [configModel getMessageClassName:messageObjectName];
- return className;
- }
- /**
- * 接收到消息的回调
- */
- - (void)didReceiveMessageNotification:(NSNotification *)notification {
- NSDictionary *dic = notification.object; /// __block TXLiveMessageModel *liveMessage
- NSDictionary *content = [dic ks_dictionaryValueForKey:@"message"];
- NSString *objectName = [content ks_stringValueForKey:@"objectName"];
- NSString *className = [self getMsgClassName:objectName];
-
- __block TXLiveMessageModel *message = [[NSClassFromString(className) alloc] init];
- message.messageId = [dic ks_stringValueForKey:@"msgID"];
- message.groupId = [dic ks_stringValueForKey:@"groupID"];
- [message evaluateSource:content];
-
- if ([message.groupId isEqualToString:self.roomId]) {
- __weak typeof(&*self) __blockSelf = self;
- dispatch_async(dispatch_get_main_queue(), ^{
- if ([message isMemberOfClass:[TXLiveMessageLike class]]) {
- TXLiveMessageLike *likeMessage = (TXLiveMessageLike *)message;
- NSLog(@"receive like count ------- %d",likeMessage.counts);
- return;
- }
- else if ([message isMemberOfClass:[TXLiveMessageLikeCount class]]) {
- return;
- }
- else if ([message isMemberOfClass:[TXLiveMessageWelcome class]]) {
- TXLiveMessageWelcome *welcomeMessage = (TXLiveMessageWelcome *)message;
- // 过滤自己发送的欢迎消息
- if ([welcomeMessage.userInfo.sendUserId isEqualToString:UserDefault(IM_USERID)]) {
- return;
- }
-
- if ([welcomeMessage.userInfo.sendUserId isEqual:__blockSelf.createrId]) { // 如果是老师 重置连麦申请状态
- [__blockSelf resetMicWaitToNomal];
- __blockSelf.isCreateInRoom = YES;
- }
- NSString *userName = [welcomeMessage.userInfo.sendUserName stringByAppendingString:@""];
- NSString *contentMsg = [NSString stringWithFormat:@"%@ 进入直播间",userName];
- [__blockSelf showAnimationView:YES showMessag:contentMsg];
- return;
- }
- // 用户退出消息
- else if ([message isMemberOfClass:[TXLiveMessageLeave class]]) {
- // TXLiveMessageLeave *userLeaveMsg = (TXLiveMessageLeave *)message;
- // if ([userLeaveMsg.userInfo.sendUserId isEqualToString:__blockSelf.createrId]) {
- // __blockSelf.isCreateInRoom = NO;
- // // 下麦
- // if (__blockSelf.micStatus == MICSTATUS_CONNECTING) {
- // [__blockSelf downSeatAction];
- // }
- // }
- return;
- }
- // 用户退出回调
- else if ([message isMemberOfClass:[TXLiveMessageUserQuit class]]) {
- // TXLiveMessageUserQuit *userLeaveMsg = (TXLiveMessageUserQuit *)message;
- // if ([userLeaveMsg.targetId isEqualToString:__blockSelf.createrId]) {
- // __blockSelf.isCreateInRoom = NO;
- // // 下麦
- // if (__blockSelf.micStatus == MICSTATUS_CONNECTING) {
- // [__blockSelf downSeatAction];
- // }
- // }
- return;
- }
-
- else if ([message isMemberOfClass:[TXLiveMessageMemberUp class]]) {
- return;
- }
- else if ([message isMemberOfClass:[TXLiveMessageStatSync class]]) { // 数据同步 不取点赞数
- return;
- }
- else if ([message isMemberOfClass:[TXLiveMessageKickOut class]]) {
- TXLiveMessageKickOut *kickMessage = (TXLiveMessageKickOut *)message;
- NSString *currentUserId = UserDefault(IM_USERID);
- if ([kickMessage.targetId isEqualToString:currentUserId]) {
- __blockSelf.micStatus = MICSTATUS_NOMAL;
- [__blockSelf kickOutLiveRoom];
- }
- return;
- }
- // 禁言控制
- else if ([message isMemberOfClass:[TXLiveMessageChatBan class]]) {
- TXLiveMessageChatBan *banMessage = (TXLiveMessageChatBan *)message;
- if (banMessage.chatBan) { // 禁止发言
- __blockSelf.enableChat = NO;
- }
- else { // 开启发言
- __blockSelf.enableChat = YES;
- }
- [__blockSelf insertMessage:banMessage];
- }
- // 连麦控制消息
- else if ([message isMemberOfClass:[TXLiveMessageSeatControl class]]) {
- TXLiveMessageSeatControl *seatControlMessage = (TXLiveMessageSeatControl *)message;
- if (seatControlMessage.seatBan) { // 禁止连麦
- __blockSelf.enableSeat = NO;
- // 未连麦情况下才重置
- if (__blockSelf.micStatus != MICSTATUS_CONNECTING) {
- // 如果在申请 发送取消申请消息
- if (__blockSelf.micStatus == MICSTATUS_WAITING) {
- [__blockSelf sendSeatMessageApply:NO];
- }
- __blockSelf.micStatus = MICSTATUS_NOMAL;
- }
- [__blockSelf hideApplyView];
- [__blockSelf hideApplyingView];
- }
- else { // 开启连麦
- __blockSelf.enableSeat = YES;
- }
- [__blockSelf insertMessage:seatControlMessage];
- }
- else if ([message isMemberOfClass:[TXLiveMessageSeatApply class]]) {
-
- // 只处理主讲人发起的连麦邀请或取消操作
- TXLiveMessageSeatApply *seatApplyMessage = (TXLiveMessageSeatApply *)message;
- NSLog(@"----- RCChatroomSeatApply type:%ld audienceName:%@ ",seatApplyMessage.type,seatApplyMessage.audienceName);
- // 只处理和自己相关的消息
- if (![seatApplyMessage.audienceId isEqualToString:UserDefault(IM_USERID)]) {
- // 刷新麦序
- return;
- }
- if (seatApplyMessage.type == SEATHANDLE_INVITE) { // 主讲人发起申请
- NSString *titles = [NSString stringWithFormat:@"%@邀请您连麦",[NSString returnNoNullStringWithString:seatApplyMessage.teacherName]];
- [__blockSelf showInviteAlertMessage:titles];
- }
- else if (seatApplyMessage.type == SEATHANDLE_DISINVITE) { // 主讲人撤回申请
- [LOADING_MANAGER MBShowAUTOHidingInWindow:@"主讲人撤回了连麦申请"];
- [__blockSelf closeAlertView];
- if (__blockSelf.micStatus == MICSTATUS_CONNECTING) {
- [__blockSelf downSeatAction];
- }
- }
- else if (seatApplyMessage.type == SEATHANDLE_KICKSEAT) { // 主讲人断开连麦
- [__blockSelf kickSeatWithMessage:@"主讲人断开连麦"];
- }
- [__blockSelf hideApplyingView];
- [__blockSelf insertMessage:seatApplyMessage];
- }
- else if ([message isMemberOfClass:[TXLiveMessageSeatResponse class]]) { // 只处理主讲人的回应
- TXLiveMessageSeatResponse *seatResponseMessage = (TXLiveMessageSeatResponse *)message;
- NSLog(@"----- RCChatroomSeatResponse type:%ld audienceName:%@ ",seatResponseMessage.type,seatResponseMessage.audienceName);
- if (![seatResponseMessage.audienceId isEqualToString:UserDefault(IM_USERID)]) { // 只处理和自己相关的消息
- return;
- }
- if (seatResponseMessage.type == SEATRESPONSE_TEACHERAPPROVE && __blockSelf.micStatus == MICSTATUS_WAITING) { //
- [__blockSelf hideApplyingView];
- [__blockSelf connectHostWithStatus:YES];
- [__blockSelf insertMessage:seatResponseMessage];
- }
- else if (seatResponseMessage.type == SEATRESPONSE_TEACHERREJECT) {
- [LOADING_MANAGER MBShowAUTOHidingInWindow:@"主讲人拒绝了您的连麦申请"];
- // 处理连麦状态
- [__blockSelf connectHostWithStatus:NO];
- [__blockSelf insertMessage:seatResponseMessage];
- }
- }
- else if ([message isMemberOfClass:[TXLiveMessageDownSeat class]]) { // 成员主动下麦消息
- return;
- }
- else if ([message isMemberOfClass:[TXLiveMessageClose class]]) { // 直播间已关闭
- [LOADING_MANAGER MBShowAUTOHidingInWindow:@"直播已结束"];
- dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.0f * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
- // 显示直播间关闭状态
- [__blockSelf closeAlertView];
- [__blockSelf displayCloseView];
- [__blockSelf hideApplyingView];
- });
- return;
- }
- else if ([message isMemberOfClass:[TXLiveTextMessage class]]) {
- TXLiveTextMessage *textMessage = (TXLiveTextMessage *)message;
- [__blockSelf insertMessage:textMessage];
- }
- else if ([message isMemberOfClass:[TXLiveMessageCardMessage class]]) {
- TXLiveMessageCardMessage *cardMessage = (TXLiveMessageCardMessage *)message;
- [__blockSelf sendCardMessage:cardMessage.goodsContent];
- }
- else if ([message isMemberOfClass:[TXLiveMessagePauseLive class]]) { // 主讲人暂停直播
- // __blockSelf.isPauseLive = YES;
- // if (__blockSelf.micStatus == MICSTATUS_WAITING) {
- // [__blockSelf sendSeatMessageApply:NO];
- // }
- // [__blockSelf resetNetTips];
- // [__blockSelf resetConnectionStatus];
- // [__blockSelf closeAlertView];
- // [__blockSelf hideApplyingView];
- // [__blockSelf changeEmptyStatusView];
- // [__blockSelf closePlayStatus];
- return;
- }
- else if ([message isMemberOfClass:[TXLiveMessageOpenLive class]]) { // 开始直播
- // __blockSelf.isPauseLive = NO;
- // __blockSelf.isCreateInRoom = YES;
- // [__blockSelf resetNetTips];
- // [__blockSelf hideEmptyView];
- // [__blockSelf startPlay];
- return;
- }
- else if ([message isMemberOfClass:[TXLiveMessageShopRush class]]) { //
- TXLiveMessageShopRush *rushMsg = (TXLiveMessageShopRush *)message;
-
- NSString *contentMsg = [NSString stringWithFormat:@"%@ 正在抢购",[NSString returnNoNullStringWithString:rushMsg.userInfo.sendUserName]];
- [__blockSelf showAnimationView:NO showMessag:contentMsg];
- }
- else if ([message isMemberOfClass:[TXLiveMessageBlockUser class]]) { // 黑名单
- TXLiveMessageBlockUser *blockMessage = (TXLiveMessageBlockUser *)message;
- if ([blockMessage.userId isEqualToString:UserDefault(IM_USERID)]) {
- __blockSelf.blacklistFlag = YES;
- [__blockSelf resetConnectionStatus];
- }
- }
- else if ([message isMemberOfClass:[TXLiveMessageUnBlockUser class]]) {
- TXLiveMessageUnBlockUser *unBlockMessage = (TXLiveMessageUnBlockUser *)message;
- if ([unBlockMessage.userId isEqualToString:UserDefault(IM_USERID)]) {
- __blockSelf.blacklistFlag = NO;
- }
- }
- else if ([message isMemberOfClass:[TXLiveMessageDownSeatAll class]]) { // 所有麦上用户下麦
- TXLiveMessageDownSeatAll *downSeatMessage = (TXLiveMessageDownSeatAll *)message;
- if (__blockSelf.micStatus == MICSTATUS_CONNECTING) {
- [__blockSelf kickSeatWithMessage:@"主讲人断开连麦"];
- [__blockSelf insertMessage:downSeatMessage];
- }
- }
- else if ([message isMemberOfClass:[TXLiveMessageRejectAllSeat class]]) { // 拒绝所有连麦申请
- TXLiveMessageRejectAllSeat *rejectAllMessage = (TXLiveMessageRejectAllSeat *)message;
- if (__blockSelf.micStatus == MICSTATUS_WAITING) {
- [LOADING_MANAGER MBShowAUTOHidingInWindow:@"主讲人拒绝了您的连麦申请"];
- // 处理连麦状态
- __blockSelf.micStatus = MICSTATUS_NOMAL;
- [__blockSelf insertMessage:rejectAllMessage];
- [__blockSelf hideApplyingView];
- }
- }
- else if ([message isMemberOfClass:[TXControlMemberMic class]]) { // 控制学生麦克风
- TXControlMemberMic *micCtrlMsg = (TXControlMemberMic *)message;
- // 如果是控制当前学生的mic
- if ([micCtrlMsg.userId isEqualToString:UserDefault(IM_USERID)]) {
- [__blockSelf changeCurrentMicStatus:micCtrlMsg.muteMic];
- }
- }
- else if ([message isMemberOfClass:[TXLiveForceKickMsg class]]) {
- TXLiveForceKickMsg *changeMsg = (TXLiveForceKickMsg *)message;
-
- if (changeMsg.targetIds.count == 0 || changeMsg.targetIds == nil) { // 如果是全员
- [__blockSelf courseChangeTips:changeMsg];
- }
- else {
- for (NSString *userId in changeMsg.targetIds) { // 如果部分学员中包含自己
- if ([userId isEqualToString:UserDefault(IM_USERID)]) {
- [__blockSelf courseChangeTips:changeMsg];
- break;
- }
- }
- }
- }
- });
- }
- }
- - (void)courseChangeTips:(TXLiveForceKickMsg *)msg {
- // 显示直播间关闭状态
- [self closeAlertView];
- [self displayCloseView];
- [self hideApplyingView];
- // 退出房间
- NSString *tipsMsg = [NSString isEmptyString:msg.reason] ? @"当前课程已调整,请退出直播间" : msg.reason;
- MJWeakSelf;
- self.closeAlert = [LiveRoomConfirmAlert liveroomAlertWithTitle:tipsMsg sureTitle:@"确定" inView:self.view confirm:^{
- [weakSelf exitRoom];
- [weakSelf.navigationController dismissViewControllerAnimated:YES completion:nil];
- }];
- }
- - (void)changeCurrentMicStatus:(BOOL)isMute {
- if (isMute == !self.micEnable) { // 如果麦克风状态和当前状态一致,剔除
- return;
- }
- if (_trtcCloud && self.isAudience == NO) {
- self.micEnable = !self.micEnable;
- [self.trtcCloud muteLocalAudio:!self.micEnable];
- NSString *desc = @"";
- if (self.micEnable) {
- desc = @"主讲人已将您的麦克风开启";
- }
- else {
- desc = @"主讲人已将您的麦克风关闭";
- }
- [LOADING_MANAGER MBShowAUTOHidingInWindow:desc];
- [self syncMicStatus:!self.micEnable];
- }
- }
- - (void)didReceiveGroupMessage:(NSNotification *)notification {
-
- NSDictionary *dic = notification.object; /// __block TXLiveMessageModel *liveMessage
-
- NSString *groupId = [dic ks_stringValueForKey:@"groupID"];
- NSDictionary *content = [dic ks_dictionaryValueForKey:@"message"];
- if ([groupId isEqualToString:self.roomId]) {
- [self evaluateGroupInfo:content];
- }
- }
- - (void)evaluateGroupInfo:(NSDictionary *)groupInfo {
- // 主播在房间
- if ([[groupInfo ks_stringValueForKey:@"LIVE_STATUS"] isEqualToString:@"ON"]) { // 直播中
- self.isPauseLive = NO;
- if (self.isAudience) {
- [self startPlay];
- }
- }
- else if ([[groupInfo ks_stringValueForKey:@"LIVE_STATUS"] isEqualToString:@"OFF"]) { // 暂停直播
- self.isPauseLive = YES;
- [self closePlayStatus];
- }
-
- // 摄像头状态
- if ([[groupInfo ks_stringValueForKey:@"ANCHOR_CAMERA"] isEqualToString:@"OFF"]) {
- self.isCreaterVideoEnable = NO;
- }
- else {
- self.isCreaterVideoEnable = YES;
- }
-
- // 禁言状态
- if ([[groupInfo ks_stringValueForKey:@"GLOBAL_BAN"] isEqualToString:@"ON"]) {
- self.enableChat = NO;
- }
- else {
- self.enableChat = YES;
- }
- // 在线人数
- if ([[groupInfo allKeys] containsObject:@"MEMBER_ONLINE"]) {
- self.totalCount = [groupInfo ks_integerValueForKey:@"MEMBER_ONLINE"];
- [self countMemberCount];
- }
-
- [self changeEmptyStatusView];
-
-
- // 主播全员闭麦状态
- if ([[groupInfo allKeys] containsObject:@"ANCHOR_MIC"]) {
- if ([[groupInfo ks_stringValueForKey:@"ANCHOR_MIC"] isEqualToString:@"ON"]) { // 禁麦
- if (self.muteRoomMic == NO) {
- self.muteRoomMic = YES;
- }
- }
- else {
- if (self.muteRoomMic == YES) {
- self.muteRoomMic = NO;
- }
- }
- }
- else {
- if (self.muteRoomMic == YES) {
- self.muteRoomMic = NO;
- }
- }
-
- // 禁止连麦
- if ([[groupInfo allKeys] containsObject:@"BAN_LINK_MIC"]) {
- if ([[groupInfo ks_stringValueForKey:@"BAN_LINK_MIC"] isEqualToString:@"ON"]) { // 禁止
- self.enableSeat = NO;
- }
- else {
- self.enableSeat = YES;
- }
- }
- else {
- self.enableSeat = YES;
- }
-
- }
- - (void)setMuteRoomMic:(BOOL)muteRoomMic {
- _muteRoomMic = muteRoomMic;
- [self changeCurrentMicStatus:muteRoomMic];
- }
- // 群属性变更信息
- - (void)didReceiveGroupCountMessage:(NSNotification *)notification {
- NSDictionary *dic = notification.object; /// __block TXLiveMessageModel *liveMessage
-
- NSString *groupId = [dic ks_stringValueForKey:@"groupID"];
- NSDictionary *content = [dic ks_dictionaryValueForKey:@"message"];
- if ([groupId isEqualToString:self.roomId]) {
- [self evaluateGroupCount:content];
- }
- }
- - (void)evaluateGroupCount:(NSDictionary *)groupCount {
- // 点赞数据
- if ([[groupCount allKeys] containsObject:@"LIKES"]) {
- self.likeCount = [groupCount ks_integerValueForKey:@"LIKES"];
- [self countLikeMessageCount];
- }
- }
- - (void)closePlayStatus {
- if (self.micStatus == MICSTATUS_WAITING) {
- [self sendSeatMessageApply:NO];
- }
- [self resetNetTips];
- [self resetConnectionStatus];
- [self closeAlertView];
- [self hideApplyingView];
- if (self.isAudience) {
- [self stopPlay];
- }
- else {
- if (_trtcCloud) {
- [self.trtcCloud stopAllRemoteView];
- [self.trtcCloud stopLocalAudio];
- [self.trtcCloud exitRoom];
- }
- }
- }
- - (void)kickOutLiveRoom {
- [LOADING_MANAGER MBShowAUTOHidingInWindow:@"您已被踢出直播间"];
- dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.5f * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
- [self quitRoom];
- });
- }
- #pragma mark ------ message operation
- - (void)resetConnectionStatus {
- if (self.micStatus == MICSTATUS_CONNECTING) {
- dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.0f * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
- [self sendDownSeatMsg];
- [self connectHostWithStatus:NO];
- });
- }
- else {
- self.micStatus = MICSTATUS_NOMAL;
- [self removeSeatContainer];
- }
- }
- - (void)resetMicWaitToNomal {
- if (self.micStatus == MICSTATUS_WAITING) {
- self.micStatus = MICSTATUS_NOMAL;
- }
- }
- - (void)tipsTeacherLeaveRoom {
- [LOADING_MANAGER MBShowAUTOHidingInWindow:@"主讲人已离开房间"];
- }
- - (void)hideApplyView {
- if (self.applyView.isShow) {
- [self.applyView hideView];
- }
- }
- - (void)hideApplyingView {
- if (self.applyingView.isShow) {
- [self.applyingView hideView];
- }
- }
- - (void)closeAlertView {
- if (self.alertView && self.alertView.isShow) {
- if (self.alertView.isQuitAlert == NO) {
- [self.alertView removeFromSuperview];
- self.alertView = nil;
- }
- }
- }
- - (void)displayCloseView {
- self.isCloseRoom = YES;
- [self hideTipsView];
- // 移除连麦视图
- [self removeSeatContainer];
- if (self.micStatus != MICSTATUS_NOMAL) {
- self.micStatus = MICSTATUS_NOMAL;
- if (_trtcCloud) {
- [self.trtcCloud stopLocalAudio];
- [self.trtcCloud exitRoom];
- }
- }
- [self stopPlay];
- self.videoView.hidden = YES;
- self.endView.hidden = NO;
- [self setDefaultBottomViewStatus];
-
- [[NSNotificationCenter defaultCenter] postNotificationName:@"LiveroomClose" object:nil];
- }
- - (void)sendCardMessage:(NSArray *)content {
- // if (_webContainer) {
- // NSMutableDictionary *sendParm = [NSMutableDictionary dictionary];
- // [sendParm setValue:@"cardChange" forKey:@"api"];
- // [sendParm setValue:content forKey:@"content"];
- // [self.webContainer postMessage:sendParm];
- // }
- }
- - (void)showInviteAlertMessage:(NSString *)tipsMessage {
- if (self.alertView && self.alertView.isShow) {
- [self.alertView removeFromSuperview];
- self.alertView = nil;
- }
- MJWeakSelf;
- self.alertView = [LiveAlertView shareInstance];
- [self.alertView alertWithTitle:@"连麦邀请" desc:tipsMessage leftButtonTitle:@"取消" rightTitle:@"确定" inView:self.view cancel:^{
- weakSelf.micStatus = MICSTATUS_NOMAL;
- [weakSelf sendSeatResponseMessage:NO];
- } confirm:^{
- [weakSelf sendSeatResponseMessage:YES];
- }];
- }
- - (void)sendSeatResponseMessage:(BOOL)isApprove {
- SEATRESPONSE type = isApprove ? SEATRESPONSE_AUDIENCEAPPROVE : SEATRESPONSE_AUDIENCEREJECT;
- TXLiveMessageSeatResponse *responseMessage = [[TXLiveMessageSeatResponse alloc] init];
- responseMessage.userInfo = [self getCurrentUser];
- responseMessage.type = type;
- responseMessage.audienceId = UserDefault(IM_USERID);
- responseMessage.audienceName = UserDefault(NicknameKey);
- MJWeakSelf;
- [self sendCustomMessage:responseMessage priority:V2TIM_PRIORITY_HIGH displayMessage:YES callback:^(BOOL success) {
- if (success) {
- if (isApprove) {
- [weakSelf connectHostWithStatus:YES];
- }
- }
- }];
-
- }
- - (void)kickSeatWithMessage:(NSString *)message {
- [LOADING_MANAGER MBShowAUTOHidingInWindow:message];
- [self sendDownSeatMsg];
- [self connectHostWithStatus:NO];
- }
- - (void)insertMessage:(TXLiveMessageModel *)liveMessage {
- [self appendAndDisplayMessage:liveMessage];
- }
- #pragma mark table data source
- - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
- return self.conversationDataRepository.count;
- }
- - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
- TXLiveMessageModel *model = [self.conversationDataRepository objectAtIndex:indexPath.row];
- TXLiveChatListCell *cell = [tableView dequeueReusableCellWithIdentifier:@"TXLiveChatListCell"];
- if (!cell) {
- cell = [[TXLiveChatListCell appearance] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"TXLiveChatListCell"];
- }
- if ([model isMemberOfClass:[TXConstMessage class]] || [model isMemberOfClass:[TXLiveTextMessage class]] || [model isMemberOfClass:[TXLiveMessageWelcome class]] || [model isMemberOfClass:[TXLiveMessageLike class]] || [model isMemberOfClass:[TXLiveMessageSeatControl class]] ||[model isMemberOfClass:[TXLiveMessageChatBan class]] || [model isMemberOfClass:[TXLiveMessageSeatApply class]] || [model isMemberOfClass:[TXLiveMessageSeatResponse class]] || [model isMemberOfClass:[TXLiveMessageShopRush class]] || [model isMemberOfClass:[TXLiveMessageDownSeatAll class]] || [model isMemberOfClass:[TXLiveMessageRejectAllSeat class]] ){
- [cell setDataModel:model createrId:self.createrId];
- }
-
- return cell;
- }
- #pragma mark ----- lazying
- - (TRTCCloud *)trtcCloud {
- if (!_trtcCloud) {
- _trtcCloud = [TRTCCloud sharedInstance];
- [_trtcCloud addDelegate:self];
- }
- return _trtcCloud;
- }
- - (V2TXLivePlayer *)livePlayer {
- if (!_livePlayer) {
- _livePlayer = [[V2TXLivePlayer alloc] init];
- [_livePlayer enableReceiveSeiMessage:YES payloadType:243];
- [_livePlayer setObserver:self];
-
- }
- return _livePlayer;
- }
- - (UIView *)videoContainerView {
- if (!_videoContainerView) {
- _videoContainerView = [[UIView alloc] initWithFrame:CGRectZero];
- _videoContainerView.backgroundColor = [UIColor clearColor];
- }
- return _videoContainerView;
- }
- - (UIView *)videoView {
- if (!_videoView) {
- _videoView = [[UIView alloc] initWithFrame:CGRectZero];
- _videoView.backgroundColor = HexRGB(0x1a1a1a);
- }
- return _videoView;
- }
- - (TXLiveVideoView *)videoRenderView {
- if (!_videoRenderView) {
- _videoRenderView = [[TXLiveVideoView alloc] initWithFrame:CGRectZero];
- }
- return _videoRenderView;
- }
- - (LiveRoomHeadView *)headView {
- if (!_headView) {
- _headView = [LiveRoomHeadView shareInstance];
- MJWeakSelf;
- [_headView quitAction:^{
- [weakSelf showQuitAlert];
- }];
- }
- return _headView;
- }
- - (void)showQuitAlert {
- if (self.isCloseRoom) { // 如果直播结束 直接点击退出房间
- [self quitRoom];
- }
- else if (self.micStatus == MICSTATUS_CONNECTING) {
- [self quitAction];
- }
- else {
- MJWeakSelf;
- self.alertView = [LiveAlertView shareInstance];
- self.alertView.isQuitAlert = YES;
- [self.alertView alertWithTitle:@"确定要退出直播间吗?" desc:@"退出后如再次观看可重新进入~" leftButtonTitle:@"取消" rightTitle:@"确认" inView:self.view cancel:^{
-
- } confirm:^{
- [weakSelf quitAction];
-
- }];
-
- }
- }
- - (void)quitRoom {
- KSDragWindowManager *manager = [KSDragWindowManager sharedManager];
- if (manager.hasShowWindow) {
- [manager resignDragWindow];
- }
-
- if (self.landScape) {
- [self changeOrientation:!self.landScape];
- dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.5f * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
- // 退出房间
- [self exitRoom];
- [self.navigationController dismissViewControllerAnimated:YES completion:nil];
- });
- }
- else {
- // 退出房间
- [self exitRoom];
- [self.navigationController dismissViewControllerAnimated:YES completion:nil];
- }
- }
- // 顶部退出房间
- - (void)quitAction {
- if (self.micStatus == MICSTATUS_CONNECTING) {
- MJWeakSelf;
- self.alertView = [LiveAlertView shareInstance];
- [self.alertView alertWithTitle:@"提示" desc:@"连麦中,是否退出房间?" leftButtonTitle:@"取消" rightTitle:@"确定" inView:self.view cancel:^{
-
- } confirm:^{
- [weakSelf quitRoom];
-
- }];
- }
- else {
- [self quitRoom];
- }
-
- }
- - (void)exitRoom {
- if (self.isAudience) {
- [self stopPlay];
- }
- else {
- if (_trtcCloud) {
- [self.trtcCloud stopLocalAudio];
- [self.trtcCloud exitRoom];
- }
- }
- TXLiveMessageLeave *leaveMsg = [[TXLiveMessageLeave alloc] init];
- leaveMsg.userInfo = [self getCurrentUser];
- MJWeakSelf;
- [self sendCustomMessage:leaveMsg priority:V2TIM_PRIORITY_NORMAL displayMessage:NO callback:^(BOOL success) {
- // quit 接口
- [weakSelf quitNotiferService];
- [weakSelf quitChatRoom];
- }];
- }
- - (void)quitChatRoom {
- [[V2TIMManager sharedInstance] quitGroup:self.roomId succ:^{
-
- } fail:^(int code, NSString *desc) {
-
- }];
- }
- - (LiveRoomBottomView *)bottomView {
- if (!_bottomView) {
- _bottomView = [LiveRoomBottomView shareInstance];
- MJWeakSelf;
- [_bottomView bottomClickAction:^(LIVEROOMACTION action) {
- [weakSelf bottomViewAction:action];
- }];
- }
- return _bottomView;
- }
- - (void)bottomViewAction:(LIVEROOMACTION)action {
- if (self.isCloseRoom) {
- [LOADING_MANAGER MBShowAUTOHidingInWindow:@"直播已结束"];
- return;
- }
- if (action == LIVEROOMACTION_CHAT) {
- if (self.blacklistFlag == YES) {
- [LOADING_MANAGER MBShowAUTOHidingInWindow:@"您已被管理员禁言"];
- return;
- }
- if (self.enableChat) { // 判断是否全员禁言
- [_inputBar setHidden:NO];
- [_inputBar setInputBarStatus:KSBottomBarStatusKeyboard];
- }
- else {
- [LOADING_MANAGER MBShowAUTOHidingInWindow:@"管理员关闭聊天"];
- }
- }
- else if (action == LIVEROOMACTION_SEAT) { // 连麦按钮
- // 判断是否是连麦状态
- if (self.micStatus == MICSTATUS_CONNECTING) { // 连麦中
- // 是否取消连麦
- MJWeakSelf;
- self.alertView = [LiveAlertView shareInstance];
- [self.alertView alertWithTitle:@"连麦中,确认取消连麦吗?" desc:@"断开后如想再次连麦可重新发起" leftButtonTitle:@"取消" rightTitle:@"确定关闭" inView:self.view cancel:^{
-
- } confirm:^{
- [weakSelf downSeatAction];
- }];
- }
- else if (self.micStatus == MICSTATUS_WAITING) { // 连麦申请中
- // 弹窗取消申请
- [self displayApplyingView];
- }
- else {
- // 禁止聊天可以连麦(测试确认)
- if (self.blacklistFlag == YES) {
- [LOADING_MANAGER MBShowAUTOHidingInWindow:@"您已被管理员禁言"];
- return;
- }
- if (self.isPauseLive == YES) {
- [LOADING_MANAGER MBShowAUTOHidingInWindow:@"老师暂停中,暂时无法接受申请"];
- return;
- }
-
- if (self.enableSeat) {
- [self displaySeatApplyView];
- }
- else {
- [LOADING_MANAGER MBShowAUTOHidingInWindow:@"管理员关闭连麦申请"];
- }
- }
- }
- else if (action == LIVEROOMACTION_LIKE) { // 点赞
-
- [self praiseBtnPressed];
- }
- else if (action == LIVEROOMACTION_SHOP) { // shop
- [self showCartAlert];
- }
- else if (action == LIVEROOMACTION_MUTE) {
- [self muteVoiceAction];
- }
- }
- - (void)showCartAlert {
- [self.cardView showViewInView:self.view];
- }
- - (void)downSeatAction {
- [self sendDownSeatMsg];
- [self connectHostWithStatus:NO];
- }
- - (void)sendDownSeatMsg {
- TXLiveMessageDownSeat *downSeatMsg = [[TXLiveMessageDownSeat alloc] init];
- TXLiveUser *mineInfo = [self getCurrentUser];
- downSeatMsg.userInfo = mineInfo;
- downSeatMsg.audienceId = mineInfo.sendUserId;
- downSeatMsg.audienceName = mineInfo.sendUserName;
-
- [self sendCustomMessage:downSeatMsg priority:V2TIM_PRIORITY_HIGH displayMessage:NO callback:^(BOOL success) {
-
- }];
- }
- - (KSShopCardView *)cardView {
- if (!_cardView) {
- _cardView = [KSShopCardView shareInstance];
- MJWeakSelf;
- [_cardView clickAction:^(CART_TYPE type) {
- [weakSelf displayTeacherInfo:type];
- }];
- }
- return _cardView;
- }
- // tabs= practice | 陪练课 live | 直播课 video | 视频课 music | 乐谱 跳转到对应tab页
- - (void)displayTeacherInfo:(CART_TYPE)type {
- [self sendRushMessage];
- if (self.isPauseLive == NO) {
- _hasShowSuspendView = YES;
- KSDragWindowManager *manager = [KSDragWindowManager sharedManager];
- BOOL isPhoneLive = self.needSwitchButton ? NO : YES;
- [manager initDragWindowWithPhoneLive:isPhoneLive];
- manager.rootVC = (CustomNavViewController *)self.navigationController;
- [self.videoRenderView removeFromSuperview];
- [manager.dragWindow.containerView addSubview:self.videoRenderView];
- [self.videoRenderView mas_updateConstraints:^(MASConstraintMaker *make) {
- make.left.right.top.bottom.mas_equalTo(manager.dragWindow.containerView);
- }];
- [manager.dragWindow bringSubviewToFront:manager.dragWindow.cancelButton];
- }
-
- NSString *tabs = @"";
- switch (type) {
- case CART_TYPE_NONE:
- {
- tabs = @"";
- }
- break;
- case CART_TYPE_ACCOMPANY:
- {
- tabs = @"practice";
- }
- break;
- case CART_TYPE_LIVE:
- {
- tabs = @"live";
- }
- break;
- case CART_TYPE_VIDEO:
- {
- tabs = @"video";
- }
- break;
- case CART_TYPE_MUSIC:
- {
- tabs = @"music";
- }
- break;
- default:
- break;
- }
- NSString *url = @"";
- if ([NSString isEmptyString:tabs]) {
- url = [NSString stringWithFormat:@"%@%@%@", WEBHOST,@"/#/teacherHome?teacherId=",self.createrUserId];
- }
- else {
- url = [NSString stringWithFormat:@"%@%@%@&tabs=%@", WEBHOST,@"/#/teacherHome?teacherId=",self.createrUserId,tabs];
- }
- KSLiveWebViewController *ctrl = [[KSLiveWebViewController alloc] init];
- ctrl.url = url;
- [self.navigationController pushViewController:ctrl animated:YES];
- }
- - (void)sendRushMessage {
- TXLiveMessageShopRush *rushMessage = [[TXLiveMessageShopRush alloc] init];
- rushMessage.userInfo = [self getCurrentUser];
- [self sendCustomMessage:rushMessage priority:V2TIM_PRIORITY_DEFAULT displayMessage:NO callback:^(BOOL success) {
-
- }];
- }
- - (void)toDetailView:(NSString *)linkUrl {
- [self sendRushMessage];
-
- if (self.isPauseLive == NO) {
- _hasShowSuspendView = YES;
- KSDragWindowManager *manager = [KSDragWindowManager sharedManager];
- BOOL isPhoneLive = self.needSwitchButton ? NO : YES;
- [manager initDragWindowWithPhoneLive:isPhoneLive];
- manager.rootVC = (CustomNavViewController *)self.navigationController;
- [self.videoRenderView removeFromSuperview];
- [manager.dragWindow.containerView addSubview:self.videoRenderView];
- [self.videoRenderView mas_updateConstraints:^(MASConstraintMaker *make) {
- make.left.right.top.bottom.mas_equalTo(manager.dragWindow.containerView);
- }];
- [manager.dragWindow bringSubviewToFront:manager.dragWindow.cancelButton];
- }
- KSLiveWebViewController *ctrl = [[KSLiveWebViewController alloc] init];
- ctrl.url = linkUrl;
- [self.navigationController pushViewController:ctrl animated:YES];
- }
- - (void)muteVoiceAction {
- if (self.bottomView.isMute) {
- if ([self.livePlayer isPlaying]) {
- [self.livePlayer setPlayoutVolume:0];
- }
- if (_trtcCloud) {
- [self.trtcCloud muteAllRemoteAudio:YES];
- }
- }
- else {
- if ([self.livePlayer isPlaying]) {
- [self.livePlayer setPlayoutVolume:100];
- }
- if (_trtcCloud) {
- [self.trtcCloud muteAllRemoteAudio:NO];
- }
- }
- }
- - (KSLiveEmptyView *)emptyView {
- if (!_emptyView) {
- _emptyView = [[KSLiveEmptyView alloc] init];
- BOOL isPhoneLive = self.needSwitchButton ? NO : YES;
- [_emptyView dispPlayViewIsPhoneLive:isPhoneLive];
- }
- return _emptyView;
- }
- - (KSLiveEndView *)endView {
- if (!_endView) {
- _endView = [[KSLiveEndView alloc] init];
- _endView.backgroundColor = HexRGB(0x25292e);
- BOOL isPhoneLive = self.needSwitchButton ? NO : YES;
- [_endView dispPlayViewIsPhoneLive:isPhoneLive];
- }
- return _endView;
- }
- - (KSLiveBadNetView *)netBadView {
- if (!_netBadView) {
- _netBadView = [[KSLiveBadNetView alloc] init];
- BOOL isPhoneLive = self.needSwitchButton ? NO : YES;
- [_netBadView dispPlayViewIsPhoneLive:isPhoneLive];
- MJWeakSelf;
- [_netBadView configViewWithImageName:@"liveVideo_close" desc:@"视频加载失败" callback:^{
- [weakSelf resetAllConnection];
- }];
- }
- return _netBadView;
- }
- - (void)resetNetTips {
- [self hideTipsView];
- }
- - (void)showBadNetTips {
- dispatch_main_async_safe(^{
- if (self.isCloseRoom == NO) {
- if (self.netBadView.hidden == YES) {
- self.netBadView.hidden = NO;
- self.videoView.hidden = YES;
- }
- }
- });
- }
- - (void)hideTipsView {
- dispatch_main_async_safe(^{
- if (self.netBadView.hidden == NO) {
- self.netBadView.hidden = YES;
- self.videoView.hidden = NO;
- }
- })
-
- }
- // 黑名单
- - (void)setBlacklistFlag:(BOOL)blacklistFlag {
- _blacklistFlag = blacklistFlag;
- [self refreshBottomChatStatus];
- }
- - (void)refreshBottomChatStatus {
- if (self.bottomView) {
- NSString *tipsTitle = self.blacklistFlag ? @"您已被管理员禁言" : @"快来互动吧!";
- self.bottomView.tipsLabel.text = tipsTitle;
- self.bottomView.tipsLabel.lineBreakMode = NSLineBreakByTruncatingMiddle;
- }
- }
- - (void)resetAllConnection {
- [self resetNetTips];
- // 清理视图
- [self hideEmptyView];
- [self removeSeatContainer];
-
- // 立刻房间后重新加入房间
- [self startPlay];
- }
- - (LOTAnimationView *)animationView {
- if (!_animationView) {
- _animationView = [LOTAnimationView animationWithFilePath:[[NSBundle bundleWithPath:[[NSBundle mainBundle] pathForResource:@"LiveCard" ofType:@"bundle"]] pathForResource:@"cardAnimation" ofType:@"json"]];
- _animationView.loopAnimation = YES;
- }
- return _animationView;
- }
- - (UIButton *)switchButton {
- if (!_switchButton) {
- _switchButton = [UIButton buttonWithType:UIButtonTypeCustom];
- [_switchButton setImage:[UIImage imageNamed:@"live_switch"] forState:UIControlStateNormal];
- [_switchButton addTarget:self action:@selector(transferToLandscape) forControlEvents:UIControlEventTouchUpInside];
- }
- return _switchButton;
- }
- - (UIView *)messageContentView {
- if (!_messageContentView) {
- _messageContentView = [[UIView alloc] init];
- [_messageContentView setBackgroundColor: [UIColor clearColor]];
- }
- return _messageContentView;
- }
- - (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:[TXLiveChatListCell class] forCellReuseIdentifier:@"TXLiveChatListCell"];
- }
- return _conversationMessageTableView;
- }
- - (NSMutableArray<TXLiveMessageModel *> *)conversationDataRepository {
- if (!_conversationDataRepository) {
- _conversationDataRepository = [NSMutableArray array];
- }
- return _conversationDataRepository;
- }
- - (TXSeatContainerView *)seatContainer {
- if (!_seatContainer) {
- _seatContainer = [[TXSeatContainerView alloc] init];
- MJWeakSelf;
- [_seatContainer seatActionCallback:^(NSString * _Nonnull userId, BOOL muteMic) {
- [weakSelf muteUserAction:userId muteStatus:muteMic];
- }];
- }
- return _seatContainer;
- }
- - (void)muteUserAction:(NSString *)userId muteStatus:(BOOL)muteMic {
- [self micButtonAction:muteMic];
- TXMicStatusSync *ctrlMsg = [[TXMicStatusSync alloc] init];
- ctrlMsg.userInfo = [self getCurrentUser];
- ctrlMsg.userId = userId;
- ctrlMsg.muteMic = muteMic;
- [self sendCustomMessage:ctrlMsg priority:V2TIM_PRIORITY_HIGH displayMessage:NO callback:^(BOOL success) {
-
- }];
- }
- - (KSChatInputBarControl *)inputBar {
- if (!_inputBar) {
- _inputBar = [[KSChatInputBarControl alloc] initWithStatus:KSBottomBarStatusDefault];
- [_inputBar setDelegate:self];
- }
- return _inputBar;
- }
- - (void)setMicStatus:(MICSTATUS)micStatus {
- _micStatus = micStatus;
- if (self.bottomView) {
- switch (micStatus) {
- case MICSTATUS_NOMAL:
- {
- [self.bottomView.seatButton setImage:[UIImage imageNamed:@"seat_image"] forState:UIControlStateNormal];
- }
- break;
- case MICSTATUS_WAITING:
- {
- [self.bottomView.seatButton setImage:[UIImage imageNamed:@"seat_connecting"] forState:UIControlStateNormal];
- }
- break;
- case MICSTATUS_CONNECTING:
- {
- [self.bottomView.seatButton setImage:[UIImage imageNamed:@"seat_connected"] forState:UIControlStateNormal];
- }
- break;
- default:
- break;
- }
- }
- }
- #pragma mark ----- 人数和点赞数统计
- - (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;
- }
- /**
- * 判断消息是否在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 ---- dealloc
- - (void)dealloc {
- NSLog(@"---- live room dealloc");
- [[NSNotificationCenter defaultCenter] removeObserver:self];
- if (_livePlayer) {
- [self.livePlayer stopPlay];
- _livePlayer = nil;
- }
- if (_trtcCloud) {
- [self.trtcCloud stopAllRemoteView];
- [self.trtcCloud stopLocalAudio];
- [self.trtcCloud exitRoom];
- [self.trtcCloud removeDelegate:self];
- _trtcCloud = nil;
- [TRTCCloud destroySharedInstance];
- }
- }
- #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 {
- if (self.blacklistFlag == YES) {
- [self setDefaultBottomViewStatus];
- return;
- }
- NSDate *date = [NSDate date];
- NSTimeInterval currentInterval = [date timeIntervalSince1970];
- if (currentInterval - self.lastSendMsgTime < 3) {
- [LOADING_MANAGER MBShowAUTOHidingInWindow:@"您说话太快啦"];
- return;
- }
-
- if (self.lastSendMsgTime == 0) {
- self.lastSendMsgTime = currentInterval;
- }
-
- if (text.length > 40) {
- [LOADING_MANAGER MBShowAUTOHidingInWindow:@"聊天消息需在40个字以内哦"];
- return;
- }
- if (self.enableChat) {
- self.lastSendMsgTime = currentInterval;
- [self touristSendMessage:text];
- }
- else {
- [self setDefaultBottomViewStatus];
- }
- }
- - (void)touristSendMessage:(NSString *)text {
- TXLiveTextMessage *message = [[TXLiveTextMessage alloc] init];
- message.userInfo = [self getCurrentUser];
- message.text = text;
- MJWeakSelf;
- [self sendTextMessage:message priority:V2TIM_PRIORITY_NORMAL displayMessage:YES callback:^(BOOL success) {
- [weakSelf setDefaultBottomViewStatus];
- }];
- }
- - (TXLiveUser *)getCurrentUser {
- TXLiveUser *user = [[TXLiveUser alloc] init];
- user.sendUserId = UserDefault(IM_USERID);
- user.sendUserName = UserDefault(NicknameKey);
- user.avatarUrl = UserDefault(AvatarUrlKey);
- return user;
- }
- /**
- 点赞
- */
- - (void)praiseBtnPressed {
- if (self.enableLike == NO) {
- [LOADING_MANAGER MBShowAUTOHidingInWindow:@"管理员已关闭点赞功能"];
- return;
- }
- NSTimeInterval currentTime = [[NSDate date] timeIntervalSince1970];
- __weak __typeof(&*self)weakSelf = self;
- dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.21 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
- if ([[NSDate date] timeIntervalSince1970] - self.lastClickPraiseTime >= 0.2) {
- [weakSelf modifyLikeCount:clickPraiseBtnTimes];
- clickPraiseBtnTimes = 0;
- }
- });
- clickPraiseBtnTimes++;
- self.lastClickPraiseTime = currentTime;
- [self presentLikeMessageAnimation];
- }
- - (void)modifyLikeCount:(NSInteger)count {
- [[V2TIMManager sharedInstance] increaseGroupCounter:self.roomId key:@"LIKES" value:count succ:^(NSDictionary<NSString *,NSNumber *> *groupCounters) {
-
- } fail:^(int code, NSString *desc) {
-
- }];
- }
- /**
- 赞动画
- */
- - (void)presentLikeMessageAnimation {
- LiveRoomLikeLayer *layer = [[LiveRoomLikeLayer alloc] initWithName:@"Like"];
- [self.videoContainerView.layer addSublayer:layer];
- CGRect tempFrame = [self.videoContainerView convertRect:self.bottomView.likeButton.frame fromView:self.bottomView];
- CGFloat width = tempFrame.size.width;
- CGFloat height = tempFrame.size.height;
-
- CGFloat dx = CGRectGetMidX(tempFrame) - width *0.5;
- CGFloat dy = CGRectGetMidY(tempFrame) - 8 - height;
- layer.frame = CGRectMake(dx, dy, width, height);
- [layer startAnimation];
- }
- - (void)displaySeatApplyView {
- [self.applyView showInView:self.view];
- }
- - (void)displayApplyingView {
- [self.applyingView showInView:self.view];
- }
- - (LiveApplyView *)applyView {
- if (!_applyView) {
- _applyView = [LiveApplyView shareInstance];
- MJWeakSelf;
- [_applyView applySeatCallback:^{
- [weakSelf applySeatAction];
- }];
- }
- return _applyView;
- }
- - (void)applySeatAction {
- [self sendSeatMessageApply:YES];
- }
- - (void)sendSeatMessageApply:(BOOL)isApply {
- if (self.micStatus == MICSTATUS_CONNECTING) {
- [LOADING_MANAGER MBShowAUTOHidingInWindow:@"您已上麦"];
- return;
- }
- SEATHANDLE type = isApply ? SEATHANDLE_APPLY : SEATHANDLE_CANCELAPPLY;
- TXLiveMessageSeatApply *applyMessage = [[TXLiveMessageSeatApply alloc] init];
- applyMessage.type = type;
- applyMessage.audienceId = UserDefault(IM_USERID);
- applyMessage.audienceName = UserDefault(NicknameKey);
- applyMessage.audienceAvatar = UserDefault(AvatarUrlKey);
- applyMessage.teacherId = self.createrId;
- applyMessage.teacherName = self.createrName;
- applyMessage.userInfo = [self getCurrentUser];
- MJWeakSelf;
- [self sendCustomMessage:applyMessage priority:V2TIM_PRIORITY_HIGH displayMessage:YES callback:^(BOOL success) {
- if (success) {
- weakSelf.micStatus = isApply ? MICSTATUS_WAITING : MICSTATUS_NOMAL;
- }
- }];
- }
- - (LiveApplyingView *)applyingView {
- if (!_applyingView) {
- _applyingView = [LiveApplyingView shareInstance];
- NSString *avatar = UserDefaultObjectForKey(AvatarUrlKey);
- [_applyingView.myAvatal sd_setImageWithURL:[NSURL URLWithString:[avatar getUrlEndcodeString]] placeholderImage:[UIImage imageNamed:USERDEFAULT_LOGO]];
- [_applyingView.teacherAvatal sd_setImageWithURL:[NSURL URLWithString:[self.createrAvatal getUrlEndcodeString]] placeholderImage:[UIImage imageNamed:USERDEFAULT_LOGO]];
- MJWeakSelf;
- [_applyingView cancleApplyCallback:^{
- [weakSelf cancleApplyAction];
- }];
- }
- return _applyingView;
- }
- - (void)cancleApplyAction {
- MJWeakSelf;
- self.alertView = [LiveAlertView shareInstance];
- [self.alertView alertWithTitle:@"连麦申请中,确认取消连麦申请吗?" desc:@"断开后如想再次连麦可重新发起" leftButtonTitle:@"取消" rightTitle:@"确定关闭" inView:self.view cancel:^{
-
- } confirm:^{
- [weakSelf.applyingView hideView];
- [weakSelf sendSeatMessageApply:NO];
- }];
- }
- #pragma mark ---- sendMessage/showMessage
- // 文本消息
- - (void)sendTextMessage:(TXLiveMessageModel *)messageContent priority:(V2TIMMessagePriority)priority displayMessage:(BOOL)displayMessage callback:(void(^)(BOOL success))callback {
- NSData *msgData = [messageContent encodeMessage];
- if (msgData == nil) {
- return;
- }
- __weak typeof(&*self) __weakself = self;
- [TXLiveMessageCenter sendLiveChatMessage:msgData groupId:self.roomId priority:priority success:^{
- dispatch_async(dispatch_get_main_queue(), ^{
-
- if (displayMessage) {
- [__weakself appendAndDisplayMessage:messageContent];
- }
- [__weakself.inputBar clearInputView];
- callback(YES);
- });
- } failer:^(int code, NSString * _Nonnull msg) {
- dispatch_async(dispatch_get_main_queue(), ^{
- [__weakself.inputBar clearInputView];
- NSLog(@"发送失败,errorcode is: %d message: %@",code, msg);
- callback(NO);
- });
- }];
- }
- // 其他消息
- - (void)sendCustomMessage:(TXLiveMessageModel *)messageContent priority:(V2TIMMessagePriority)priority displayMessage:(BOOL)displayMessage callback:(void(^)(BOOL success))callback {
- NSData *msgData = [messageContent encodeMessage];
- if (msgData == nil) {
- return;
- }
- __weak typeof(&*self) __weakself = self;
- [TXLiveMessageCenter sendLiveChatMessage:msgData groupId:self.roomId priority:priority success:^{
- dispatch_async(dispatch_get_main_queue(), ^{
-
- if (displayMessage) {
- [__weakself appendAndDisplayMessage:messageContent];
- }
- callback(YES);
- });
- } failer:^(int code, NSString * _Nonnull msg) {
- dispatch_async(dispatch_get_main_queue(), ^{
- NSLog(@"发送失败,errorcode is: %d message: %@",code, msg);
- callback(NO);
- });
- }];
- }
- /**
- * 将消息加入本地数组
- */
- - (void)appendAndDisplayMessage:(TXLiveMessageModel *)liveMessage {
- if (!liveMessage) {
- return;
- }
- if ([self appendMessageModel:liveMessage]) {
- 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:NO];
- self.isNeedScrollToButtom=NO;
- }
- }
- return;
- }
- /**
- * 如果当前会话没有这个消息id,把消息加入本地数组
- */
- - (BOOL)appendMessageModel:(TXLiveMessageModel *)model {
-
- if (!model) {
- return NO;
- }
- //这里可以根据消息类型来决定是否显示,如果不希望显示直接return NO
-
- //数量不可能无限制的大,这里限制收到消息过多时,就对显示消息数量进行限制。
- //用户可以手动下拉更多消息,查看更多历史消息。
- if (self.conversationDataRepository.count>500) {
- [self.conversationDataRepository removeObjectAtIndex:0];
- [self.conversationMessageTableView reloadData];
- }
-
- [self.conversationDataRepository addObject:model];
- return YES;
- }
- - (void)showAnimationView:(BOOL)isJoinRoom showMessag:(NSString *)message {
- if (self.landScape) {
- return;
- }
- if (self.enterAnimationView && self.enterAnimationView.isShow) {
- return;
- }
- else {
- ANIMATIONTYPE type = isJoinRoom ? ANIMATIONTYPE_JOIN : ANIMATIONTYPE_RUSH;
- self.enterAnimationView = [[LiveAnimationView alloc] initWithTitle:message animationType:type];
- [self.view addSubview:self.enterAnimationView];
- [self.enterAnimationView 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.enterAnimationView];
-
- MJWeakSelf;
- [self.enterAnimationView startAnimationEndCallback:^{
-
- weakSelf.enterAnimationView.isShow = NO;
- weakSelf.enterAnimationView = nil;
- }];
- }
- }
- - (NSMutableArray *)remoteMemberArray {
- if (!_remoteMemberArray) {
- _remoteMemberArray = [NSMutableArray array];
- }
- return _remoteMemberArray;
- }
- - (TXLiveLoadingView *)loadingView {
- if (!_loadingView) {
- _loadingView = [TXLiveLoadingView shareInstance];
- }
- return _loadingView;
- }
- - (void)showLoading {
- if (![self.videoView.subviews containsObject:self.loadingView]) {
- [self.loadingView showLoadingView:self.videoView];
- }
- }
- - (void)hideLoading {
- if ([self.videoView.subviews containsObject:self.loadingView]) {
- [self.loadingView hideLoadingView];
- }
- }
- - (void)micButtonAction:(BOOL)isMute {
- if (isMute == !self.micEnable) {
- return;
- }
- if (_trtcCloud && self.isAudience == NO) {
- self.micEnable = !isMute;
- [self.trtcCloud muteLocalAudio:!self.micEnable];
- [self syncMicStatus:!self.micEnable];
- }
- }
- - (void)syncMicStatus:(BOOL)isMute {
- TXMicStatusSync *syncMic = [[TXMicStatusSync alloc] init];
- syncMic.userInfo = [self getCurrentUser];
- syncMic.userId = UserDefault(IM_USERID);
- syncMic.muteMic = isMute;
- [self sendCustomMessage:syncMic priority:V2TIM_PRIORITY_HIGH displayMessage:NO callback:^(BOOL success) {
-
- }];
- [self renderSeatView];
- }
- #pragma mark ---- 3A config
- - (void)setSubjectId:(NSString *)subjectId {
- _subjectId = subjectId;
- // 设置 3A参数
- self.ANS = 0;
- self.AEC = 100;
- // 长号14和萨克斯5 AGC 一样
- if ([subjectId isEqualToString:@"5"] || [subjectId isEqualToString:@"14"]) {
- self.AGC = 45;
- }
- else if ([subjectId isEqualToString:@"16"]) { // 次中音号
- self.AGC = 80;
- }
- else if ([subjectId isEqualToString:@"12"]) {
- self.AGC = 50;
- }
- else {
- self.AGC = 0;
- }
- }
- /*
- #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
|