123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590 |
- //
- // NewClassRoomViewController.m
- // StudentDaya
- //
- // Created by Kyle on 2020/6/12.
- // Copyright © 2020 DayaMusic. All rights reserved.
- //
- #import "NewClassRoomViewController.h"
- #import "ClassTitleView.h"
- #import "ClassroomMainContainer.h"
- #import "ClassVideoListView.h"
- #import "KSNormalAlertView.h"
- // 聊天列表
- #import "LoginHelper.h"
- #import "ChatAreaView.h"
- #import "RTCService.h"
- #import "Classroom.h"
- #import "ClassroomService.h"
- #import <MBProgressHUD/MBProgressHUD.h>
- #import "AppDelegate.h"
- #import "KSWhiteboardControl.h"
- #import "UIDevice+TFDevice.h"
- #import "KSRemoteUserManager.h"
- #import "LocalRenderManager.h"
- #import "NSDate+Transform.h"
- #import "UIViewController+zhStatusBarStyle.h"
- #import "KSTipsView.h"
- #import "ClassroomTimerManager.h"
- #define TitleViewHeight (82)
- #define KSExamSongFileKey (@"KSDownloadAccompany")
- #define TTimeLableWidth (180)
- #define TTimeLableHeight (20)
- typedef NS_ENUM(NSInteger, ACCOMPANYACTION) {
- ACCOMPANYACTION_NONE, // 没有在播放
- ACCOMPANYACTION_SONG, // 播放原声
- ACCOMPANYACTION_ACCOMPANY, // 播放伴奏
- };
- @interface NewClassRoomViewController ()<ClassTitleViewDelegate, RCRTCRoomEventDelegate, ClassroomDelegate, ClassroomMainContainerDelegate, UIGestureRecognizerDelegate, RCRTCStatusReportDelegate, RTCServiceDelegate,KSWhiteboardControlDelegate, ClassVideoListViewDelegate,ClassroomTimerManagerDelegate,RCRTCEngineEventDelegate>
- @property (nonatomic, strong) ClassTitleView *titleView;
- @property (nonatomic, strong) ClassroomMainContainer *containerView;
- @property (nonatomic, strong) ClassVideoListView *videoListView;
- @property (nonatomic, strong) ChatAreaView *chatAreaView;
- @property (nonatomic, strong) KSWhiteboardControl *wBoardCtrl;
- @property (nonatomic, strong) MBProgressHUD *hud;
- @property (nonatomic, strong) NSMutableArray<NSNumber*>* packetLossStore;
- @property (nonatomic, strong) UILabel *networkLabel;
- @property (nonatomic, assign) BOOL cancleAlert;
- @property (nonatomic, assign) BOOL isQuitRoom; // 是否正在退出房间
- @property (nonatomic, assign) BOOL hasShowAlert;
- @property (nonatomic, assign) BOOL isSwitchLine; // 是否线路切换
- @property (nonatomic, assign) BOOL isChat;
- /** 定时器 */
- @property (nonatomic, strong) NSTimer *timer;
- /** 定时器多少秒循环一次 */
- @property (nonatomic, assign) float timerLength;
- /** 当前是否播放状态 */
- @property (nonatomic, assign) BOOL isPlay;
- /** 当前发出的声次数(用来判断播放"嘀"还是"咚"声音) */
- @property (nonatomic, assign) int currentTotalNo;
- /** 节拍类型 */
- @property (nonatomic, assign) KSMetronomeType metronomeStat;
- /** 播放速率,范围40~240 */
- @property (nonatomic, assign) int rate;
- // 播放节拍器音量
- @property (nonatomic, assign) NSInteger volume;
- /** 记录上一次的频率 */
- @property (nonatomic, assign) int lastRate;
- @property (nonatomic, strong) NSString *pathDing;
- @property (nonatomic, strong) NSString *pathDong;
- @property (nonatomic, strong) KSTipsView *tipsView;
- @property (nonatomic, strong) ClassroomTimerManager *timeManager;
- @property (nonatomic, strong) UILabel *timeLabel;
- @property (nonatomic, strong) KSNormalAlertView *alertView;
- @end
- @implementation NewClassRoomViewController
- - (void)changeOrientation:(BOOL)isLandScape {
- if (isLandScape) {
- // 切换到横屏
- AppDelegate* delegate = (AppDelegate*)[UIApplication sharedApplication].delegate;
- delegate.allowAutoRotate = YES;
- dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
- [UIDevice switchNewOrientation:UIInterfaceOrientationLandscapeRight inController:self];
- });
- }
- else {
- // 切换到横屏
- AppDelegate* delegate = (AppDelegate*)[UIApplication sharedApplication].delegate;
- delegate.allowAutoRotate = NO;
- dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
- [UIDevice switchNewOrientation:UIInterfaceOrientationPortrait inController:self];
- });
- }
- }
- #pragma mark - Life cycle
- - (void)viewWillAppear:(BOOL)animated {
- [super viewWillAppear:animated];
- self.zh_statusBarHidden = YES;
- // 切换到横屏
- [self changeOrientation:YES];
- [[UIApplication sharedApplication] setIdleTimerDisabled:YES];
- [RCRTCEngine sharedInstance].statusReportDelegate = self;
- [RCRTCEngine sharedInstance].delegate = self;
- }
- - (void)viewWillDisappear:(BOOL)animated {
- [super viewWillDisappear:animated];
- if (_isPlay) {
- [self pause];
- [self removeAll];
- }
- // 竖屏
- [self changeOrientation:NO];
- [[UIApplication sharedApplication] setIdleTimerDisabled:NO];
- self.zh_statusBarHidden = NO;
- [self hideAlertView];
- [self judgeShowAlert];
- }
- - (void)hideAlertView {
- if (self.alertView && self.alertView.isShow) {
- [self.alertView dismissAlertView];
- }
- }
- - (void)judgeShowAlert {
- if (self.cancleAlert || self.hasShowAlert) {
- return;
- }
- if (![NSString isEmptyString:self.classEndTime]) {
- NSDateFormatter *dateFormatter=[[NSDateFormatter alloc] init];
- dateFormatter.timeZone = [NSTimeZone systemTimeZone];
- [dateFormatter setDateFormat:@"yyyy-MM-dd HH:mm:ss"];
- NSDate *endDate = [dateFormatter dateFromString:self.classEndTime];
- NSDate *currentDate = [NSDate date];
- NSTimeInterval timeInterval = [currentDate timeIntervalSinceDate:endDate];
- if (timeInterval >= 0) { // 课程结束弹出评价
- self.hasShowAlert = YES;
- [[NSNotificationCenter defaultCenter] postNotificationName:@"showEvaluateAlert" object:self.courseId];
- }
- }
- }
- - (void)viewDidLoad {
- [super viewDidLoad];
- // Do any additional setup after loading the view.
-
- self.view.backgroundColor = HexRGB(0x35343e);
-
- [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(leaveRoomAction) name:@"classroomLogout" object:nil];
- [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(quitRoomAction) name:@"classroomQuit" object:nil];
-
- // 切换到横屏
- [self changeOrientation:YES];
- [self addSubviews];
- [self bindDelegates];
- [self publishStream];
- [self renderMainContainerView];
- self.timeManager.isDisplay = YES;
- [[RTCService sharedInstance] useSpeaker:YES];
- UITapGestureRecognizer *tapGes = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapGesture:)];
- [self.view addGestureRecognizer:tapGes];
- tapGes.delegate = self;
- [self showRoleHud];
- self.isQuitRoom = NO;
- [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(backgroundQuitRoomAction) name:@"backgroundQuit" object:nil];
- }
- - (void)backgroundQuitRoomAction {
- self.isQuitRoom = YES;
- self.isSwitchLine = NO;
- [[LoginHelper sharedInstance] logout:^{
- } error:^(RCRTCCode code) {
- }];
-
- self.cancleAlert = YES;
- }
- #pragma mark ----- 账号异地登陆
- - (void)leaveRoomAction {
- [self showMessage:@"该账号在其他设备上登录"];
- self.isQuitRoom = YES;
- self.isSwitchLine = NO;
- [[LoginHelper sharedInstance] logout:^{
- } error:^(RCRTCCode code) {
- }];
- self.cancleAlert = YES;
- [[NSNotificationCenter defaultCenter] postNotificationName:@"backLoginView" object:nil];
- }
- - (void)quitRoomAction {
- dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.0f * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
- self.isQuitRoom = YES;
- self.isSwitchLine = NO;
- [[LoginHelper sharedInstance] logout:^{
- } error:^(RCRTCCode code) {
- }];
- self.cancleAlert = YES;
- [[NSNotificationCenter defaultCenter] postNotificationName:@"showOtherLoginAlert" object:nil];
- });
- }
- // 提示信息
- - (void)showMessage:(NSString *)message {
- MBProgressHUD *hud = [MBProgressHUD showHUDAddedTo:self.view animated:YES];
- [self.view bringSubviewToFront:hud];
- hud.removeFromSuperViewOnHide =YES;
- hud.mode = MBProgressHUDModeText;
- hud.label.text = message;
- hud.minSize = CGSizeMake(132.f, 60.0f);
- hud.label.textColor = [UIColor whiteColor];
- hud.bezelView.style = MBProgressHUDBackgroundStyleSolidColor;
- hud.bezelView.backgroundColor = [UIColor colorWithHexString:@"#000000" alpha:0.8];
- [hud hideAnimated:YES afterDelay:2];
- }
- - (void)tapGesture: (UITapGestureRecognizer *)tapGesture {
- self.titleView.isDisplay = YES;
- self.timeManager.isDisplay = YES;
- [self hideChatAreaView];
- }
- -(BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch{
- if ([touch.view isDescendantOfView:self.chatAreaView] || [touch.view isDescendantOfView:self.videoListView]) {
- return NO;
- }
- if ([touch.view isDescendantOfView:self.wBoardCtrl.wbView] || [touch.view isDescendantOfView:self.containerView]) {
- [self tapGesture:(UITapGestureRecognizer *)gestureRecognizer];
- }
- return YES;
- }
- - (void)viewDidAppear:(BOOL)animated {
- [super viewDidAppear:animated];
- }
- - (void)showRoleHud {
- Role role = [ClassroomService sharedService].currentRoom.currentMember.role;
- if(role == RoleAudience) {
- [self.tipsView showTipsMessage:@"你当前身份是旁听人,其他人看/听不见你" inView:self.view];
-
- [self performSelector:@selector(showOnlyYouHUD) withObject:nil afterDelay:5.0f];
- }else{
- [self showOnlyYouHUD];
- }
- }
- - (void)showOnlyYouHUD {
- if ([ClassroomService sharedService].currentRoom.memberList.count == 1) {
- [self.tipsView showTipsMessage:@"当前课堂只有你一人,你可以等待或离开" inView:self.view];
- }
- }
- #pragma mark --- ClassTitleViewDelegate
- - (void)classTitleView:(UIButton *)button didTapAtTag:(ClassTitleViewActionTag)tag {
- [self.chatAreaView.inputBarControl setInputBarStatus:InputBarControlStatusDefault];
- switch (tag) {
- case ClassTitleViewActionTagMicrophone:
- {
- if (button.selected == NO) {
- if (self.alertView && self.alertView.isShow) {
- [self.alertView dismissAlertView];
- }
- self.alertView = [KSNormalAlertView ks_showAlertWithTitle:@"确认关闭麦克风吗?" leftTitle:@"取消" rightTitle:@"确认" cancel:^{
- } confirm:^{
- button.selected = YES;
- [[ClassroomService sharedService] enableDevice:NO withType:DeviceTypeMicrophone];
- }];
- }
- else {
- button.selected = NO;
- [[ClassroomService sharedService] enableDevice:YES withType:DeviceTypeMicrophone];
- }
- }
- break;
- case ClassTitleViewActionTagCamera:
- {
- if (button.selected == NO) {
- if (self.alertView && self.alertView.isShow) {
- [self.alertView dismissAlertView];
- }
- self.alertView = [KSNormalAlertView ks_showAlertWithTitle:@"确认关闭摄像头吗?" leftTitle:@"取消" rightTitle:@"确认" cancel:^{
- } confirm:^{
- button.selected = YES;
- [[ClassroomService sharedService] enableDevice:NO withType:DeviceTypeCamera];
- }];
- }
- else {
- button.selected = NO;
- [[ClassroomService sharedService] enableDevice:YES withType:DeviceTypeCamera];
- }
- }
- break;
- case ClassTitleViewActionTagSwitchLine: // 切换线路
- {
- MJWeakSelf;
- if (self.alertView && self.alertView.isShow) {
- [self.alertView dismissAlertView];
- }
- self.alertView = [KSNormalAlertView ks_showAlertWithTitle:@"确认切换线路吗?" leftTitle:@"取消" rightTitle:@"确认" cancel:^{
- } confirm:^{
- [weakSelf restartRoom];
- }];
- }
- break;
- case ClassTitleViewActionTagSwitchCamera:
- {
- [[RTCService sharedInstance] switchCamera];
- }
- break;
- case ClassTitleViewActionTagChat:
- {
- button.selected = !button.selected;
- button.selected ? [self showChatAreaView] : [self hideChatAreaView];
- self.isChat = button.selected;
- }
- break;
- case ClassTitleViewActionTagHangup:
- {
- MJWeakSelf;
- if (self.alertView && self.alertView.isShow) {
- [self.alertView dismissAlertView];
- }
- self.alertView = [KSNormalAlertView ks_showAlertWithTitle:@"确认退出课堂吗?" leftTitle:@"取消" rightTitle:@"确认" cancel:^{
- } confirm:^{
- weakSelf.isQuitRoom = YES;
- SealClassLog(@"ActionTagHangup");
- weakSelf.hud = [self createProgressHUD];
- [[LoginHelper sharedInstance] logout:^{
- } error:^(RCRTCCode code) {
- }];
- }];
- }
- break;
- default:
- break;
- }
- }
- #pragma mark ---- ClassroomTimerManager delegate
- - (void)formatTime:(NSString *)timeString {
- self.timeLabel.text = timeString;
- }
- - (void)timeLabelAddAnimation:(CABasicAnimation *)animation {
- self.timeLabel.textColor = HexRGB(0x2DC7AA);
- [self.timeLabel.layer addAnimation:animation forKey:nil];
- }
- - (void)hiddenTitleView {
- [self.titleView hiddenView];
- }
- - (void)quitClassroomNotifer {
- // 课程结束后15分钟自动退出房间 连堂课不退出(对内)
- if (self.isQuitRoom == NO) {
- self.isQuitRoom = YES;
- // 退出房间
- [self.tipsView showTipsMessage:@"课程已结束" inView:self.view];
- dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
- // 课程结束退出房间
- SealClassLog(@"ClassEnd!");
- self.hud = [self createProgressHUD];
- [[LoginHelper sharedInstance] logout:^{
- } error:^(RCRTCCode code) {
- }];
- });
- }
- }
- #pragma mark ------ 退出RTC房间并重新加入
- - (void)restartRoom {
- self.isSwitchLine = YES;
- if (_isPlay) {
- [self pause];
- [self removeAll];
- }
- self.hud = [self createProgressHUD];
- [self.wBoardCtrl.wbView leaveRoom];
- [[LoginHelper sharedInstance] logout:^{
- } error:^(RCRTCCode code) {
- }];
- }
- - (void)reJoinRTCRoom {
- dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0f * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
- NSString *roomId = [LoginHelper sharedInstance].roomId;
- NSString *userName = [LoginHelper sharedInstance].userName;
- [[ClassroomService sharedService] joinClassroom:roomId userName:userName isAudience:NO success:^(Classroom * _Nonnull classroom) {
- self.isSwitchLine = NO;
- [self restartRTCConnection];
- } error:^(ErrorCode errorCode, NSString * _Nonnull message) {
- [self.tipsView showTipsMessage:@"切换线路失败!" inView:self.view];
- [self.hud hideAnimated:YES];
- self.isSwitchLine = NO;
- }];
- });
- }
- - (void)restartRTCConnection {
-
- [[RTCService sharedInstance] joinRongRTCRoom:[ClassroomService sharedService].currentRoom.roomId success:^(RCRTCRoom * _Nonnull room) {
- [self.hud hideAnimated:YES];
- [self.tipsView showTipsMessage:@"切换线路成功" inView:self.view];
- // 重置UI 重新发布音视频流
- [LocalRenderManager shareInstance].hadRenderMainView = NO;
- self.timeManager.isDisplay = YES;
- [self publishStream];
- [self bindDelegates];
- [self.titleView refreshTitleView];
- [self.containerView refreshToolView];
- [self.hud hideAnimated:YES];
- [RCRTCEngine sharedInstance].statusReportDelegate = self;
- [RCRTCEngine sharedInstance].delegate = self;
- [[RTCService sharedInstance] useSpeaker:YES];
- [self renderMainContainerView];
- [self.videoListView reloadVideoList];
-
- } error:^(RCRTCCode code) {
- [self.hud hideAnimated:YES];
- if (code == RCRTCCodeAudioDeviceStartError) {
- [self.tipsView showTipsMessage:@"音频设备启动失败,请重启设备后重试!" inView:self.view];
- }
- else {
- [self.tipsView showTipsMessage:@"切换线路失败!" inView:self.view];
- }
- }];
- }
- #pragma mark - ClassroomDelegate
- - (void)roomDidLeave {
- NSLog(@"roomDidLeave");
- if (_isSwitchLine) {
- if ([RTCService sharedInstance].rtcRoom) {
- [[KSRemoteUserManager shareInstance] removeAllUser];
- [[RTCService sharedInstance] leaveRongRTCRoom:[ClassroomService sharedService].currentRoom.roomId success:^{
- [self reJoinRTCRoom];
- } error:^(RCRTCCode code) {
- [self.hud hideAnimated:YES];
- [self.tipsView showTipsMessage:@"切换线路失败!" inView:self.view];
- self.isSwitchLine = NO;
- }];
- }
- }
- else {
- [[KSRemoteUserManager shareInstance] removeAllUser];
- [[RCIMClient sharedRCIMClient] clearMessagesUnreadStatus:ConversationType_GROUP targetId:[ClassroomService sharedService].currentRoom.roomId];
- int unreadMsgCount = [[RCIMClient sharedRCIMClient] getUnreadCount:@[
- @(ConversationType_PRIVATE), @(ConversationType_APPSERVICE), @(ConversationType_GROUP),@(ConversationType_SYSTEM)
- ]];
- if (unreadMsgCount >= 1) {
- [(KSTabBarViewController *)self.tabBarController noteNewsWithIndex:2 count:unreadMsgCount];
- } else {
- [(KSTabBarViewController *)self.tabBarController clearNewsWithIndex:2];
- }
- // 关闭白板连接
- [self.wBoardCtrl.wbView.sdk setCommonCallbackDelegate:nil];
- [self.wBoardCtrl.wbView.room disconnect:^{
- }];
- if ([RTCService sharedInstance].rtcRoom) {
- [[RTCService sharedInstance] leaveRongRTCRoom:[ClassroomService sharedService].currentRoom.roomId success:^{
- } error:^(RCRTCCode code) {
- }];
- }
- [self dismissClassroom];
- }
- }
- - (void)dismissClassroom {
- [self.hud hideAnimated:YES];
- [ClassroomService sharedService].currentRoom = nil;
- [self dismissViewControllerAnimated:NO completion:^{
- [self.timeManager stopDurationTimer];
- [self.timeLabel.layer removeAllAnimations];
- }];
- }
- - (void)memberDidJoin:(RoomMember *)member {
- NSLog(@"memberDidJoin %@",member);
- if(member.role != RoleAudience) {
- [self.videoListView reloadVideoList];
- }
- if (member.role == RoleTeacher) {
- [self.tipsView showTipsMessage:[NSString stringWithFormat:@"老师%@已经进入教室", member.name] inView:self.view];
- if (_isPlay) {
- [self pause];
- [self removeAll];
- [[RTCService sharedInstance] playAllRemoteUserAudioStream];
- }
- if ([ClassroomService sharedService].currentRoom.isPlaySong) {
- [[RCRTCAudioMixer sharedInstance] stop];
- [ClassroomService sharedService].currentRoom.isPlaySong = NO;
- [[RTCService sharedInstance] playAllRemoteUserAudioStream];
- }
- }
- }
- - (void)memberDidLeave:(RoomMember *)member {
- NSLog(@"memberDidLeave %@",member);
- // 此处移除
- [[KSRemoteUserManager shareInstance] removeUser:member.userId];
-
- if(member.role != RoleAudience) {
- [self.videoListView reloadVideoList];
- }
- if (member.role == RoleTeacher) {
- // 老师退出房间后,学生如果在节拍器播放时停止节拍器
- if (_isPlay) {
- [self pause];
- [self removeAll];
- [[RTCService sharedInstance] playAllRemoteUserAudioStream];
- }
- if ([ClassroomService sharedService].currentRoom.isPlaySong) {
- [[RCRTCAudioMixer sharedInstance] stop];
- [ClassroomService sharedService].currentRoom.isPlaySong = NO;
- [[RTCService sharedInstance] playAllRemoteUserAudioStream];
- }
- }
- }
- - (void)memberDidKick:(RoomMember *)member {
- NSLog(@"memberDidKick %@",member);
- [[KSRemoteUserManager shareInstance] removeUser:member.userId];
- if ([ClassroomService sharedService].currentRoom.currentMember.role == RoleTeacher) {
- [self.tipsView showTipsMessage:[NSString stringWithFormat:@"你已将%@移出课堂", member.name] inView:self.view];
- }
- [self.videoListView reloadVideoList];
- if (self.containerView.member.role == member.role) {
- [self.containerView cancelRenderView];
- }
- }
- - (void)errorDidOccur:(ErrorCode)code {
- NSLog(@"errorDidOccur %@",@(code));
- [self.hud hideAnimated:YES];
- if (code != ErrorCodeSuccess) {
- if (code == ErrorCodeOverMaxUserCount) {
- [self.tipsView showTipsMessage:@"超过人数限制" inView:self.view];
- }else {
- [self.tipsView showTipsMessage:@"操作失败,请稍后再试" inView:self.view];
- }
- }
- }
- - (void)deviceDidEnable:(BOOL)enable type:(DeviceType)type forUser:(RoomMember *)member operator:(nonnull NSString *)operatorId {
- NSLog(@"deviceDidEnable devicetype:%@ enable:%@ memeber:%@",@(type),@(enable),member);
- RoomMember *curMember = [ClassroomService sharedService].currentRoom.currentMember;
- NSString *hudMessage = @"";
- //只有老师和自己才有提示
- if (curMember.role == RoleTeacher && ![curMember.userId isEqualToString:operatorId]) {
- if (type == DeviceTypeCamera) {
- hudMessage = !enable ? [NSString stringWithFormat:NSLocalizedStringFromTable(@"SetCameraClose", @"SealClass", nil),member.name] : [NSString stringWithFormat:NSLocalizedStringFromTable(@"SetCameraOpen", @"SealClass", nil),member.name];
- } else if (type == DeviceTypeMicrophone) {
- hudMessage = !enable ? [NSString stringWithFormat:NSLocalizedStringFromTable(@"SetMicorophoneClose", @"SealClass", nil),member.name] : [NSString stringWithFormat:NSLocalizedStringFromTable(@"SetMicorophoneOpen", @"SealClass", nil),member.name];
- }
- else if (type == DeviceTypeMusicMode) {
- hudMessage = !enable ? [NSString stringWithFormat:@"%@的音乐模式已关闭",member.name] : [NSString stringWithFormat:@"%@的音乐模式已开启",member.name];
- }
- [self.tipsView showTipsMessage:hudMessage inView:self.view];
- } else {
- if ([curMember.userId isEqualToString:member.userId]) {
- if (type == DeviceTypeCamera) { // 摄像头
- // 非自己操作才需要做提示
- if(![curMember.userId isEqualToString:operatorId]){
- hudMessage = !enable ? @"老师已关闭你的摄像头" : NSLocalizedStringFromTable(@"CameraOpend", @"SealClass", nil);
- [self.tipsView showTipsMessage:hudMessage inView:self.view];
- }
-
- [self.containerView refreshToolView];
- [[RTCService sharedInstance] setCameraDisable:!enable];
- } else if (type == DeviceTypeMicrophone) { // 麦克风
- // 非自己操作才需要做提示
- if(![curMember.userId isEqualToString:operatorId]){
- hudMessage = !enable ? @"老师已关闭你的麦克风" : NSLocalizedStringFromTable(@"MicorophoneOpend", @"SealClass", nil);
- [self.tipsView showTipsMessage:hudMessage inView:self.view];
- }
-
- [self.containerView refreshToolView];
- [[RTCService sharedInstance] setMicrophoneDisable:!enable];
- }
- else if (type == DeviceTypeMusicMode) {
- // 非自己操作才需要做提示
- if(![curMember.userId isEqualToString:operatorId]) {
- // hudMessage = !enable ? NSLocalizedStringFromTable(@"老师关闭了你的音乐模式", @"SealClass", nil) : NSLocalizedStringFromTable(@"音乐模式已打开", @"SealClass", nil);
- // [self.tipsView showTipsMessage:hudMessage inView:self.view];
- }
-
- [self.containerView refreshToolView];
- [self changeModeAction:enable];
- }
- else if (type == DeviceTypeHandup) {
- // if ([curMember.userId isEqualToString:operatorId]) {
- // if (enable) {
- // [self.tipsView showTipsMessage:@"您已举手" inView:self.view];
- // }
- // }
- }
- else if (type == DeviceTypeExamSong) {
- if (enable) {
- // 播放伴奏
- [self playSongAction];
- }
- else {
- // 停止伴奏
- [[RCRTCAudioMixer sharedInstance] stop];
- [self playSongEnable:NO];
- }
-
- }
- else if (type == DeviceTypeAccompany || type == DeviceTypeMusicScore) { // 原音或伴奏
- if (enable) {
- // 检测是否存在该曲目
- RoomMember *member = [ClassroomService sharedService].currentRoom.currentMember;
- NSString *songId = [NSString stringWithFormat:@"%d", member.musicScoreAccompanimentId];
- NSString *songUrl = member.url;
- NSString *accompnayUrl = member.mp3Url;
- // 播放伴奏
- [self checkAccompnayDownloadNotifer:songUrl accompanyUrl:accompnayUrl songId:songId needPlay:YES];
- }
- else {
- // 停止伴奏
- [[RCRTCAudioMixer sharedInstance] stop];
- [self playSongEnable:NO];
- }
- }
-
- }
- }
- if ([ClassroomService sharedService].currentRoom.currentDisplayType != DisplayWhiteboard && type == DeviceTypeCamera) {
- // 延迟调用,防止刷新出现灰屏
- dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
- [self renderMainContainerView];
- });
- }
- [self.titleView refreshTitleView];
- [self.containerView refreshToolView];
- }
- - (void)playSongAction {
-
- if ([ClassroomService sharedService].currentRoom.isPlaySong || [ClassroomService sharedService].currentRoom.isPlayBeat) {
- // 停止伴奏
- [[RCRTCAudioMixer sharedInstance] stop];
- }
-
- // 获取路径 播放伴奏
- RoomMember *member = [ClassroomService sharedService].currentRoom.currentMember;
- NSString *songId = [NSString stringWithFormat:@"%d", member.musicScoreAccompanimentId];
-
- NSDictionary *fileDic = UserDefaultObjectForKey(KSExamSongFileKey);
- NSDictionary *storeDic = [fileDic ks_dictionaryValueForKey:songId];
- NSString *fileName = nil;
- NSString *filePath = nil;
- if (member.accompanimentPlayStatus) {
- fileName = [[storeDic ks_dictionaryValueForKey:@"accompany"] ks_stringValueForKey:@"fileName"];
- filePath = [self getFilePathWithName:fileName];
- }
- else if (member.playStatus) {
- fileName = [[storeDic ks_dictionaryValueForKey:@"music"] ks_stringValueForKey:@"fileName"];
- filePath = [self getFilePathWithName:fileName];
- }
- // 判断文件是否存在
- NSLog(@"-------songid %@", songId);
- NSLog(@"------filePath %@", filePath);
- NSFileManager *fileManager = [NSFileManager defaultManager];
- if ([fileManager fileExistsAtPath:filePath] && ![NSString isEmptyString:fileName]) {
- NSInteger soundVolome = [ClassroomService sharedService].currentRoom.soundVolume;
- NSLog(@"soundVolome------%zd",soundVolome);
- [[RCRTCAudioMixer sharedInstance] stop];
- @try {
- // 混音伴奏音量
- [RCRTCAudioMixer sharedInstance].mixingVolume = soundVolome;
- [RCRTCAudioMixer sharedInstance].playingVolume = soundVolome;
- [[RCRTCAudioMixer sharedInstance] startMixingWithURL:[NSURL fileURLWithPath:filePath] playback:YES mixerMode:RCRTCMixerModeMixing loopCount:NSUIntegerMax];
- } @catch (NSException *exception) {
- NSLog(@"%@", exception);
- } @finally {
-
- }
-
- }
- [self playSongEnable:YES];
- }
- - (void)playSongEnable:(BOOL)enable {
- NSString *teacherId = [ClassroomService sharedService].currentRoom.teacher.userId;
- if (enable) {
- if ([ClassroomService sharedService].currentRoom.isPlayBeat) {
- [self pause];
- [self removeAll];
- }
- [ClassroomService sharedService].currentRoom.isPlaySong = YES;
- [[RTCService sharedInstance] unPlayRemoteUserAudioStreamExcept:teacherId];
- }
- else {
- [ClassroomService sharedService].currentRoom.isPlaySong = NO;
- [[RTCService sharedInstance] playAllRemoteUserAudioStream];
- }
- }
- // 请求用户打开设备,助教关闭用户设备没有回调。
- - (void)deviceDidInviteEnable:(DeviceType)type ticket:(NSString *)ticket {
- NSLog(@"deviceDidInviteEnable devicetype:%@",@(type));
- if (type == DeviceTypeCamera) {
- if (self.alertView && self.alertView.isShow) {
- [self.alertView dismissAlertView];
- }
- self.alertView = [KSNormalAlertView ks_showAlertWithTitle:@"老师邀请你打开摄像头" leftTitle:@"拒绝" rightTitle:@"同意" cancel:^{
- [[ClassroomService sharedService] rejectEnableDevice:type];
- } confirm:^{
- [[ClassroomService sharedService] approveEnableDevice:type];
- }];
- }else if (type == DeviceTypeMicrophone) {
- [self.tipsView showTipsMessage:@"老师开启了你的麦克风" inView:self.view];
- [[ClassroomService sharedService] approveEnableDevice:type];
- }
- else if (type == DeviceTypeExamSong) { // 接口自动处理同意
- }
- else if (type == DeviceTypeAccompany || type == DeviceTypeMusicScore) { // 伴奏接口自动处理成同意
-
- }
- else {
- [[ClassroomService sharedService] approveEnableDevice:type];
- }
- }
- //只有助教能收到这个回调,可以不在这里处理文字,因为设备的回调还会走
- - (void)deviceInviteEnableDidApprove:(RoomMember *)member type:(DeviceType)type {
- NSLog(@"deviceInviteEnableDidApprove devicetype:%@ member:%@ ",@(type),member);
- }
- //拒绝只有助教能收到这个回调,且只走这个回调
- - (void)deviceInviteEnableDidReject:(RoomMember *)member type:(DeviceType)type {
- NSLog(@"deviceInviteEnableDidReject devicetype:%@ member:%@ ",@(type),member);
- [self.tipsView showTipsMessage:[NSString stringWithFormat:@"%@拒绝了你的邀请",member.name] inView:self.view];
- }
- #pragma mark ----- 伴奏下载
- - (void)accompanyDownloadCallback:(NSString *)songUrl accompanyUrl:(NSString *)accompnayUrl songId:(NSString *)songId {
- [self checkAccompnayDownloadNotifer:songUrl accompanyUrl:accompnayUrl songId:songId needPlay:NO];
- }
- - (void)checkAccompnayDownloadNotifer:(NSString *)songUrl accompanyUrl:(NSString *)accompnayUrl songId:(NSString *)songId needPlay:(BOOL)isNeedPlay {
-
- if ([self checkSongHasSave:songId songUrl:songUrl accompanyUrl:accompnayUrl]) { // 判断文件是否已下载
- [[ClassroomService sharedService] adjustAccompanySongNotifer:songId status:YES];
- if (isNeedPlay) {
- dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
- [self playSongAction];
- });
- }
- }
- else { // 如果不存在则去下载
- if (![NSString isEmptyString:songUrl]) {
- [self downloadSongAction:songUrl songId:songId isAccompany:NO success:^{
-
- if (![NSString isEmptyString:accompnayUrl]) {
-
- [self downloadSongAction:accompnayUrl songId:songId isAccompany:YES success:^{
- [[ClassroomService sharedService] adjustAccompanySongNotifer:songId status:YES];
- if (isNeedPlay) {
- dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
- [self playSongAction];
- });
- }
- } faliure:^{
- [[ClassroomService sharedService] adjustAccompanySongNotifer:songId status:NO];
- }];
- }
- else {
- [[ClassroomService sharedService] adjustAccompanySongNotifer:songId status:YES];
- if (isNeedPlay) {
- dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
- [self playSongAction];
- });
- }
- }
- } faliure:^{
- [[ClassroomService sharedService] adjustAccompanySongNotifer:songId status:NO];
- }];
- }
- else if (![NSString isEmptyString:accompnayUrl]){
-
- [self downloadSongAction:accompnayUrl songId:songId isAccompany:YES success:^{
- [[ClassroomService sharedService] adjustAccompanySongNotifer:songId status:YES];
- if (isNeedPlay) {
- dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
- [self playSongAction];
- });
- }
- } faliure:^{
- [[ClassroomService sharedService] adjustAccompanySongNotifer:songId status:NO];
- }];
- }
- else { // 原声和伴奏均为空
- [[ClassroomService sharedService] adjustAccompanySongNotifer:songId status:NO];
- }
- }
- }
- - (void)downloadSongAction:(NSString *)url songId:(NSString *)songId isAccompany:(BOOL)isAccompany success:(void(^)(void))success faliure:(void(^)(void))faliure {
- [KSNetworkingManager downloadFileRequestWithFileUrl:url progress:^(int64_t bytesRead, int64_t totalBytes) {
- NSLog(@"%.2f", bytesRead *1.0 / totalBytes);
- } success:^(NSURL * _Nonnull fileUrl) {
- if ([self saveUrlWithFilePath:fileUrl songUrl:url songId:songId isAccompany:isAccompany]) {
- success();
- }
- else {
- faliure();
- }
- } faliure:^(NSError * _Nonnull error) {
- faliure();
- }];
- }
- - (BOOL)saveUrlWithFilePath:(NSURL *)fileUrl songUrl:(NSString *)songUrl songId:(NSString *)songId isAccompany:(BOOL)isAccompany {
- NSData *sourceData = [NSData dataWithContentsOfURL:fileUrl];
- NSString *cachePath = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) firstObject];
- NSString *filePath= [cachePath stringByAppendingPathComponent:@"AccompanySong"];
- // 先创建子目录
- NSFileManager *fileManager = [NSFileManager defaultManager];
- if (![fileManager fileExistsAtPath:filePath]) {
- [fileManager createDirectoryAtPath:filePath withIntermediateDirectories:YES attributes:nil error:nil];
- }else{
- NSLog(@"已创建文件夹");
- }
- NSString *fileName = [[songUrl componentsSeparatedByString:@"/"] lastObject];
- NSString *tempPath = [filePath stringByAppendingPathComponent:fileName];
- BOOL success = [sourceData writeToFile:tempPath atomically:NO];
- if (success) {
- NSDictionary *fileDic = UserDefaultObjectForKey(KSExamSongFileKey); // 只能存NSDictionary
- NSMutableDictionary *storeDic = [NSMutableDictionary dictionary];
- if (!fileDic) {
- fileDic = [NSMutableDictionary dictionary];
- }
- else {
- storeDic = [NSMutableDictionary dictionaryWithDictionary:[fileDic ks_dictionaryValueForKey:songId]];
- }
-
- NSDictionary *parm = @{@"url" : songUrl,
- @"fileName" : fileName};
- NSString *keyString = isAccompany ? @"accompany" :@"music";
- [storeDic setValue:parm forKey:keyString];
-
- NSMutableDictionary *saveDic = [NSMutableDictionary dictionaryWithDictionary:fileDic];
- [saveDic setValue:storeDic forKey:songId];
-
- UserDefaultSetObjectForKey(saveDic, KSExamSongFileKey);
- }
- return success;
- }
- - (NSString *)getFilePathWithName:(NSString *)fileName {
- NSString *cachePath = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) firstObject];
- NSString *filePath= [cachePath stringByAppendingPathComponent:@"AccompanySong"];
- return [filePath stringByAppendingPathComponent:fileName];;
- }
- - (BOOL)checkSongHasSave:(NSString *)songId songUrl:(NSString *)songUrl accompanyUrl:(NSString *)accompanyUrl {
- BOOL hasSaveFile = NO;
- NSMutableDictionary *fileDic = UserDefaultObjectForKey(KSExamSongFileKey);
- NSDictionary *storeDic = [fileDic ks_dictionaryValueForKey:songId];
- NSFileManager *fileManager = [NSFileManager defaultManager];
- if (![NSString isEmptyString:songUrl]) {
- NSString *fileName = [[storeDic ks_dictionaryValueForKey:@"music"] ks_stringValueForKey:@"fileName"];
- NSString *filePath = [self getFilePathWithName:fileName];
- if ([[fileDic allKeys] containsObject:songId] && [fileManager fileExistsAtPath:filePath] && ![NSString isEmptyString:fileName]) {
- hasSaveFile = YES;
- }
- else {
- hasSaveFile = NO;
- }
- }
- if (![NSString isEmptyString:accompanyUrl]) {
- NSString *fileName = [[storeDic ks_dictionaryValueForKey:@"accompany"] ks_stringValueForKey:@"fileName"];
- NSString *filePath = [self getFilePathWithName:fileName];
- if ([[fileDic allKeys] containsObject:songId] && [fileManager fileExistsAtPath:filePath] && ![NSString isEmptyString:fileName]) {
- hasSaveFile = YES;
- }
- else {
- hasSaveFile = NO;
- }
- }
- return hasSaveFile;
- }
- #pragma mark - private method
- - (void)bindDelegates {
- self.titleView.delegate = self;
- [[RTCService sharedInstance] setRTCRoomDelegate:self];
- [RTCService sharedInstance].delegate = self;
- [ClassroomService sharedService].classroomDelegate = self;
- }
- - (void)addSubviews {
- [self.view addSubview:self.containerView];
- [self.view addSubview:self.timeLabel];
- [self.containerView bringSubviewToFront:self.timeLabel];
- [self.view addSubview:self.titleView];
- [self wBoardCtrl];
- [self chatAreaView];
- [self.view addSubview:self.videoListView];
- [self.view bringSubviewToFront:self.titleView];
- }
- - (void)showChatAreaView{
- [self.view addSubview:self.chatAreaView];
- }
- - (void)hideChatAreaView{
- [UIView animateWithDuration:0.2 animations:^{
- self.titleView.chatBtn.selected = NO;
- [self.chatAreaView removeFromSuperview];
- }];
- }
- - (CGRect)mainContainerViewFrame {
- CGFloat x = iPhoneXSafeTopMargin;
- CGFloat y = 0;
- CGFloat width = KLandscapeWidth - x - iPhoneXSafeBottomMargin;
- CGFloat height = KLandscapeHeight - y;
- return CGRectMake(x, y, width, height);
- }
- - (void)displayWhiteboard:(NSString *)boardId {
- CGRect frame = [self getWBoardFrame];
- [self.wBoardCtrl loadWBoardWithFrame:frame name:boardId];
- for (UIView * view in self.view.subviews) {
- if ([view isKindOfClass:[ChatAreaView class]]) {
- [self.view bringSubviewToFront:view];
- }
- }
- [self.view bringSubviewToFront:self.timeLabel];
- }
- - (CGRect)getWBoardFrame {
- CGRect mainVideoFrame = self.containerView.currentVideoFrame;
- mainVideoFrame.origin.x += iPhoneXSafeTopMargin;
- mainVideoFrame.origin.y = 10;
- return mainVideoFrame;
- }
- - (void)publishStream {
- if ([ClassroomService sharedService].currentRoom.currentMember.role != RoleAudience) {
- [[RTCService sharedInstance] publishLocalUserDefaultAVStream];
- }
- }
- - (void)renderMainContainerView {
- self.titleView.onShowLabel.hidden = YES;
- RoomMember *teacher = [ClassroomService sharedService].currentRoom.teacher;
- if ([ClassroomService sharedService].currentRoom.currentDisplayType == DisplayTypeStudent) {
- // 将之前订阅的流切换成小流
- [self changeLastDisplayToTinyStream];
- // 有打开的屏幕
- for (RoomMember *displayMember in [ClassroomService sharedService].currentRoom.memberList) {
- if ([displayMember.userId isEqualToString:[ClassroomService sharedService].currentRoom.currentDisplayURI]) {
- if ([displayMember.userId isEqualToString:[ClassroomService sharedService].currentRoom.currentMember.userId]) {
- self.titleView.onShowLabel.hidden = NO;
- // 重置举手状态
- [ClassroomService sharedService].currentRoom.currentMember.handUpOn = NO;
- [self.containerView refreshToolView];
- }
- [self.wBoardCtrl hideBoard];
- [self.containerView containerViewRenderView:displayMember];
- [self.videoListView showTeacherPrompt:NO];
- break;
- }
- }
-
- }
- else {
- // 将之前订阅的流切换成小流
- [self changeLastDisplayToTinyStream];
-
- if (([ClassroomService sharedService].currentRoom.currentDisplayType == DisplayTeacher && teacher.cameraEnable)) {
- NSLog(@"%@",[ClassroomService sharedService].currentRoom.currentDisplayURI);
- [self.wBoardCtrl hideBoard];
- [self.containerView containerViewRenderView:[ClassroomService sharedService].currentRoom.teacher];
- [self.videoListView showTeacherPrompt:YES];
- } else if ([ClassroomService sharedService].currentRoom.currentDisplayType == DisplayWhiteboard) {
- [self.containerView cancelRenderView];
- [self displayWhiteboard:[ClassroomService sharedService].currentRoom.currentDisplayURI];
- [self.videoListView showTeacherPrompt:NO];
- } else if (([ClassroomService sharedService].currentRoom.currentDisplayType == DisplaySharedScreen)) {
- [self.wBoardCtrl hideBoard];
- [[RTCService sharedInstance] renderUserSharedScreenOnView:self.containerView.videoView forUser:[ClassroomService sharedService].currentRoom.currentDisplayURI];
- // 分享视频
- [self.videoListView showTeacherPrompt:NO];
- } else {
- [self.wBoardCtrl hideBoard];
- [self.containerView cancelRenderView];
- }
- }
- }
- - (void)changeLastDisplayToTinyStream {
- RoomMember *lastMember = self.containerView.member;
- if (![NSString isEmptyString:lastMember.userId] && ![lastMember.userId isEqualToString:[ClassroomService sharedService].currentRoom.currentDisplayURI] && ![lastMember.userId isEqualToString:[ClassroomService sharedService].currentRoom.currentMember.userId]) {
- [[RTCService sharedInstance] exchangeRemoteUserAVStreamToTinySteam:lastMember.userId callback:^{
-
- }];
- }
- }
- - (void)whiteboardDidDisplay:(NSString *)boardId {
- NSLog(@"whiteboardDidDisplay %@ ",boardId);
- [self renderMainContainerView];
- }
- - (void)sharedScreenDidDisplay:(NSString *)userId {
- NSLog(@"sharedScreenDidDisplay %@ ",userId);
- [self renderMainContainerView];
- }
- - (void)studentDidDisplay:(NSString *)studentId {
- NSLog(@"studentDidDisplay %@", studentId);
- [self renderMainContainerView];
- }
- - (void)teacherDidDisplay {
- NSLog(@"teacherDidDisplay %@ ",[ClassroomService sharedService].currentRoom.teacher.userId);
- [self renderMainContainerView];
- }
- - (void)noneDidDisplay {
- NSLog(@"noneDidDisplay");
- [self renderMainContainerView];
- }
- - (void)checkNodePlayAndSongDownload {
- RoomMember *currentMember = [ClassroomService sharedService].currentRoom.currentMember;
- if (currentMember.enable) {
- // 延迟播放
- dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0f * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
- [self playNode:currentMember.enable rate:currentMember.rate beatType:currentMember.customType volume:currentMember.volume];
- });
- }
- else {
-
- if (currentMember.musicScoreAccompanimentId != 0) { // 如果有记录当前播放曲目
- BOOL needPlay = currentMember.accompanimentPlayStatus || currentMember.playStatus;
- [self checkAccompnayDownloadNotifer:currentMember.url accompanyUrl:currentMember.mp3Url songId:[NSString stringWithFormat:@"%d", currentMember.musicScoreAccompanimentId] needPlay:needPlay];
- }
- }
- }
- // 播放节拍器的回调
- - (void)playNodeAction:(BOOL)enable userId:(NSString *)userId rate:(int)rate beatType:(BeatType)type volume:(NSInteger)volume {
- NSLog(@"playNodeAction userId:%@ enable:%@ beatType:%@ rate:%@ volume:%@",userId,@(enable),@(type), @(rate), @(volume));
- RoomMember *curMember = [ClassroomService sharedService].currentRoom.currentMember;
- if (curMember.role == RoleStudent) {
- if ([NSString isEmptyString:userId]) { // 操作全部
- [self playNode:enable rate:rate beatType:type volume:volume];
- }
- else {
- NSArray *userIdArray = [userId componentsSeparatedByString:@","];
- for (NSString *subUserId in userIdArray) {
- if ([curMember.userId isEqualToString:subUserId]) { // 操作个人
- [self playNode:enable rate:rate beatType:type volume:volume];
- break;
- }
- }
- }
- }
- }
- - (void)playNode:(BOOL)enable rate:(int)rate beatType:(BeatType)type volume:(NSInteger)volume {
- NSString *teacherId = [ClassroomService sharedService].currentRoom.teacher.userId;
- if (enable) {
- if ([ClassroomService sharedService].currentRoom.isPlaySong) { // 停止当前伴奏播放
- [ClassroomService sharedService].currentRoom.isPlaySong = NO;
- [[RCRTCAudioMixer sharedInstance] stop];
- }
- [self setMetronomeStat:type];
- [self setRate:rate];
- self.volume = volume;
- [self.videoListView updateBeatNode:type beat:rate];
- [self play];
-
- [[RTCService sharedInstance] unPlayRemoteUserAudioStreamExcept:teacherId];
- }
- else {
- [self pause];
- [self removeAll];
- [[RTCService sharedInstance] playAllRemoteUserAudioStream];
- }
- }
- #pragma mark --- RTCServiceDelegate 自己发布流成功回调
- - (void)successPublishLocalStream {
- dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
- // 检测是否需要通知
- [self notiferTeacherRefreshSongStatus];
-
- [self checkNodePlayAndSongDownload];
- });
- }
- - (void)notiferTeacherRefreshSongStatus {
- NSArray *songArray = [ClassroomService sharedService].currentRoom.currentMember.songMessage;
- if (songArray.count) {
- [[ClassroomService sharedService] adjustAccompanySongNotifer:nil status:YES];
- }
- }
- #pragma mark - RongRTCRoomDelegate
- - (void)didPublishStreams:(NSArray <RCRTCInputStream *>*)streams {
-
- NSString *displayUserId;
- if (([ClassroomService sharedService].currentRoom.currentDisplayType == DisplayTeacher)) {
- displayUserId = [ClassroomService sharedService].currentRoom.teacher.userId;
- }
- else if ([ClassroomService sharedService].currentRoom.currentDisplayType == DisplayTypeStudent) {
- displayUserId = [ClassroomService sharedService].currentRoom.currentDisplayURI;
- }
- // 当用户非正常退出的时候,如果再次进入需要重新订阅流
- RCRTCInputStream *firstStream = [streams lastObject];
- if ([[KSRemoteUserManager shareInstance] isContentUser:firstStream.userId]) {
- [[KSRemoteUserManager shareInstance] removeUser:firstStream.userId];
- }
-
- for (RCRTCInputStream *stream in streams) {
- if (stream.mediaType == RTCMediaTypeVideo) {
- if ([stream.userId isEqualToString:displayUserId]) {
- [self renderMainContainerView];
- }
- [self.videoListView updateUserVideo:stream.userId];
- }
- }
- }
- - (void)didConnectToStream:(RCRTCInputStream *)stream {
- if (stream.streamId && stream.streamId.length > 0) {
- NSLog(@"didConnectToStream userId:%@ streamID:%@",stream.userId,stream.streamId);
- }
- }
- #pragma mark ----- ClassVideoListViewDelegate
- - (void)videoListView:(ClassVideoListView *)view didTap:(RoomMember *)member {
- self.titleView.isDisplay = YES;
- self.timeManager.isDisplay = YES;
- /*
- // 将视频投到主屏幕上
- NSString *currentDisplayUserId = member.userId;
- NSString *lastDisplayUserId = [ClassroomService sharedService].currentRoom.currentDisplayURI;
-
- if([currentDisplayUserId isEqualToString:lastDisplayUserId]) {
- [self.videoListView updateUserVideo:lastDisplayUserId];
- return;
- }
- DisplayType type = member.role == RoleTeacher ? DisplayTeacher : DisplayTypeStudent;
- [ClassroomService sharedService].currentRoom.currentDisplayURI = currentDisplayUserId;
- [ClassroomService sharedService].currentRoom.currentDisplayType = type;
- // 如果之前有切换成大流的视频
- if (![NSString isEmptyString:lastDisplayUserId] && ![lastDisplayUserId isEqualToString:[ClassroomService sharedService].currentRoom.currentMemberId]) {
- [[RTCService sharedInstance] exchangeRemoteUserAVStreamToTinySteam:lastDisplayUserId];
- }
-
- if(![[ClassroomService sharedService].currentRoom.currentMemberId isEqualToString:member.userId]) {
- // 记录当前播放音频的学生
- [ClassroomService sharedService].currentRoom.currentPlayUserId = currentDisplayUserId;
- [[RTCService sharedInstance] exchangeRemoteUserAVStreamToNomalSteam:member.userId];
- }
- [self renderMainContainerView];
- */
- }
- #pragma mark - Getters & setters
- - (ClassroomTimerManager *)timeManager {
- if (!_timeManager) {
- _timeManager = [[ClassroomTimerManager alloc] initWithDelegate:self];
-
- _timeManager.autoClose = [ClassroomService sharedService].currentRoom.autoCloseFlag;
- // 统一15分钟关闭
- _timeManager.autoCloseNetworkRoomTime = [ClassroomService sharedService].currentRoom.autoCloseNetworkRoomTime;
- }
- return _timeManager;
- }
- - (UILabel *)timeLabel {
- if (!_timeLabel) {
- _timeLabel = [[UILabel alloc] initWithFrame:CGRectMake(KLandscapeWidth - self.videoListView.width - 40 - TTimeLableWidth - iPhoneXSafeBottomMargin, 25, TTimeLableWidth, TTimeLableHeight)];
- _timeLabel.font = [UIFont systemFontOfSize:16];
- _timeLabel.textAlignment = NSTextAlignmentRight;
- _timeLabel.textColor = HexRGB(0xFF5500);
- }
- return _timeLabel;
- }
- - (KSTipsView *)tipsView {
- if (!_tipsView) {
- _tipsView = [[KSTipsView alloc] initWithFrame:CGRectZero];
- }
- return _tipsView;
- }
- - (ClassTitleView *)titleView {
- if (!_titleView) {
- _titleView = [[ClassTitleView alloc] initWithFrame:CGRectMake(iPhoneXSafeTopMargin, 0, KLandscapeWidth - iPhoneXSafeTopMargin - iPhoneXSafeBottomMargin, TitleViewHeight)];
- }
- return _titleView;
- }
- - (ClassVideoListView *)videoListView {
- if(!_videoListView) {
- CGFloat width = 0.0f;
- CGFloat height = 0.0f;
- height = KLandscapeHeight - 10;
- width = height / 3.0f * 4;
- if (width > KLandscapeWidth - 160) {
- width = KLandscapeWidth - 160;
- }
- _videoListView = [[ClassVideoListView alloc] initWithFrame:CGRectMake(width + iPhoneXSafeTopMargin + 5, 10, KLandscapeWidth - (width + 10 + iPhoneXSafeTopMargin) - iPhoneXSafeBottomMargin, height)];
- _videoListView.delegate = self;
- }
- return _videoListView;
- }
- - (ClassroomMainContainer *)containerView {
- if (!_containerView) {
- _containerView = [[ClassroomMainContainer alloc] initWithFrame:[self mainContainerViewFrame]];
- _containerView.delegate = self;
- }
- return _containerView;
- }
- - (ChatAreaView *)chatAreaView {
- if(!_chatAreaView) {
- _chatAreaView = [[ChatAreaView alloc] initWithFrame:CGRectMake(KLandscapeWidth - iPhoneXSafeBottomMargin - 300,0, 300, KLandscapeHeight) conversationType:ConversationType_GROUP targetId:[ClassroomService sharedService].currentRoom.roomId];
- }
- return _chatAreaView;
- }
- - (KSWhiteboardControl *)wBoardCtrl {
- if (!_wBoardCtrl) {
- CGRect frame = [self getWBoardFrame];
- _wBoardCtrl = [[KSWhiteboardControl alloc] initWithDelegate:self viewFrame:frame];
- NSString *roomId = [ClassroomService sharedService].currentRoom.roomId;
- _wBoardCtrl.roomId = roomId;
- _wBoardCtrl.isRatationImage = self.isRorationImage;
- [_wBoardCtrl moveToSuperView:self.view];
- }
- return _wBoardCtrl;
- }
- #pragma mark ---- 网络监测
- - (void)didReportStatusForm:(RCRTCStatusForm *)form {
- const CGFloat lossRateBase = 0.15;
- if (self.packetLossStore.count + form.sendStats.count > 10) {
- NSInteger diff = (self.packetLossStore.count + form.sendStats.count) - 10;
- [self.packetLossStore removeObjectsInRange:NSMakeRange(0,diff)];
- }
-
- for (RCRTCStreamStat* stat in form.sendStats) {
- [self.packetLossStore addObject:@(stat.packetLoss)];
- }
-
- float totalSum = 0;
- for (NSNumber* lossRate in self.packetLossStore) {
- totalSum += [lossRate floatValue];
- }
-
- if (totalSum > 0 && self.packetLossStore.count) {
- float avgLoss = totalSum / self.packetLossStore.count;
- [self showNetworkingStatus:avgLoss];
- if (avgLoss > lossRateBase) { // 网络质量不佳
-
- dispatch_async(dispatch_get_main_queue(), ^{
- [self.view addSubview:self.networkLabel];
- [self.view bringSubviewToFront:self.networkLabel];
- self.networkLabel.hidden = NO;
- self.networkLabel.text = @"当前通话连接质量不佳";
- });
- }
- else { // 正常
- dispatch_async(dispatch_get_main_queue(), ^{
- self.networkLabel.hidden = YES;
- self.networkLabel.text = @"";
- [self.networkLabel removeFromSuperview];
- });
- }
- }
- }
- - (void)showNetworkingStatus:(float)packageLose {
- dispatch_async(dispatch_get_main_queue(), ^{
- if (packageLose < 0.05) {
- self.titleView.netStatus = NetWorkingStatus_Good;
- }
- else if (packageLose <= 0.1) {
- self.titleView.netStatus = NetWorkingStatus_Well;
- }
- else if (packageLose <= 0.15) {
- self.titleView.netStatus = NetWorkingStatus_Bad;
- }
- else {
- self.titleView.netStatus = NetWorkingStatus_Poor;
- }
- });
- }
- - (NSMutableArray<NSNumber*>*)packetLossStore {
- if (!_packetLossStore) {
- _packetLossStore = [[NSMutableArray alloc] initWithCapacity:10];
- }
- return _packetLossStore;
- }
- - (UILabel *)networkLabel {
- if (!_networkLabel) {
- _networkLabel = [[UILabel alloc] initWithFrame:CGRectMake((KLandscapeWidth - 200) / 2.0f, (KLandscapeHeight - 60) / 2.0f, 200, 60)];
- _networkLabel.backgroundColor = HexRGBAlpha(0x000000, 0.8f);
- _networkLabel.textColor = HexRGB(0xffffff);
- _networkLabel.textAlignment = NSTextAlignmentCenter;
- _networkLabel.font = [UIFont systemFontOfSize:14.0f];
- _networkLabel.layer.cornerRadius = 5.0f;
- }
- return _networkLabel;
- }
- #pragma mark ---- 修改声音模式
- - (void)changeModeAction:(BOOL)enable {
- if (enable) { // 音乐模式切换
- [[RCRTCEngine sharedInstance].defaultAudioStream setAudioQuality:RCRTCAudioQualityMusicHigh Scenario:RCRTCAudioScenarioMusicClassRoom];
- }
- else {
- [[RCRTCEngine sharedInstance].defaultAudioStream setAudioQuality:RCRTCAudioQualityMusicHigh Scenario:RCRTCAudioScenarioDefault];
- }
- }
- - (void)dealloc {
- [[NSNotificationCenter defaultCenter] removeObserver:self];
- if (_timer) {
- [_timer invalidate];
- _timer = nil;
- }
- }
- - (void)setMetronomeStat:(KSMetronomeType)metronomeStat {
- _metronomeStat = metronomeStat;
-
- self.currentTotalNo = 0;
-
- if (_timer && _isPlay) {
-
- [self resetTimer];
- }
- }
- - (void)setRate:(int)rate{
-
- _rate = rate;
-
- CGFloat rateFloat = rate;
-
- self.timerLength = 1 /(rateFloat /60);
-
- if (self.lastRate == 0) {
-
- self.lastRate = _rate;
- }
-
- // 超过10间隔再重置定时器,设置最新间隔秒数
- if (abs(self.lastRate -_rate) >= 10 && _isPlay) {
-
- self.lastRate = _rate;
-
- [self resetTimer];
- }
-
- if (abs(self.lastRate -_rate) >= 10 && !_isPlay) {
-
- if (_timer) {
- [_timer invalidate];
- _timer = nil;
- }
- }
- }
- - (void)play{
-
- _isPlay = YES;
- [ClassroomService sharedService].currentRoom.isPlayBeat = YES;
- [self.timer setFireDate:[NSDate distantPast]];
- }
- - (void)pause{
- [[RCRTCAudioMixer sharedInstance] stop];
- [self.timer setFireDate:[NSDate distantFuture]];//暂停计时器
- _isPlay = NO;
- [ClassroomService sharedService].currentRoom.isPlayBeat = NO;
- }
- - (NSTimer *)timer{
-
- if (!_timer) {
-
- _timer = [NSTimer scheduledTimerWithTimeInterval:self.timerLength target:self selector:@selector(timerAction) userInfo:nil repeats:YES];
- [[NSRunLoop currentRunLoop] addTimer:_timer forMode:NSRunLoopCommonModes];
- }
- return _timer;
- }
- - (void)timerAction {
-
- if (_metronomeStat ==KSMetronomeType1V4) {
- [self playAction:YES];
- }
- else {
- if (_metronomeStat == KSMetronomeType2V4 && self.currentTotalNo %2 == 0) {
- [self playAction:YES];
- }else if (_metronomeStat == KSMetronomeType3V4 && self.currentTotalNo %3 == 0){
- [self playAction:YES];
- }else if (_metronomeStat == KSMetronomeType4V4 && self.currentTotalNo %4 == 0){
- [self playAction:YES];
- }else if (_metronomeStat == KSMetronomeType6V8 && self.currentTotalNo %6 == 0){
- [self playAction:YES];
- }else{
- [self playAction:NO];
- }
- }
- [self.videoListView showBeatNode:self.currentTotalNo];
- self.currentTotalNo ++;
- }
- - (void)playAction:(BOOL)isDing {
- dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
- NSString *path = isDing ? self.pathDing : self.pathDong;
- [[RCRTCAudioMixer sharedInstance] stop];
- @try {
- [RCRTCAudioMixer sharedInstance].mixingVolume = self.volume;
- [RCRTCAudioMixer sharedInstance].playingVolume = self.volume;
- [[RCRTCAudioMixer sharedInstance] startMixingWithURL:[NSURL fileURLWithPath:path] playback:YES mixerMode:RCRTCMixerModeMixing loopCount:1];
- } @catch (NSException *exception) {
- NSLog(@"%@", exception);
- } @finally {
- }
-
- });
- }
- - (NSString *)pathDing {
- if (!_pathDing) {
- _pathDing = [[NSBundle mainBundle] pathForResource:@"tick" ofType:@"wav"];
- }
- return _pathDing;
- }
- - (NSString *)pathDong {
- if (!_pathDong) {
- _pathDong = [[NSBundle mainBundle] pathForResource:@"tock" ofType:@"wav"];
- }
- return _pathDong;
- }
- #pragma mark -- 重置定时器
- - (void)resetTimer {
-
- [_timer invalidate];
- _timer = nil;
- [self.timer setFireDate:[NSDate distantPast]];
- }
- - (void)removeAll {
-
- if (_timer) {
- [_timer invalidate];
- _timer = nil;
- }
- }
- #pragma mark --- KSWhiteboardControlDelegate
- - (void)didTurnPage:(NSInteger)pageNum {
-
- }
- - (void)whiteboardViewDidChangeZoomScale:(float)scale {
-
- }
- // 白板连接状态回调
- - (void)connectionWhiteboardStatus:(JOINROOMSTATUS)status {
- if (status == JOINROOMSTATUS_FAILED) {
- [self.tipsView showTipsMessage:@"白板连接失败,请检查您的网络" inView:self.view];
- }
- else if (status == JOINROOMSTATUS_PARAMERROR) {
- [self.tipsView showTipsMessage:@"获取白板参数错误" inView:self.view];
- }
- }
- #pragma mark -- mainContainer
- - (void)mainContainerOpertionMember:(RoomMember *)member tapButton:(UIButton *)button {
- // 🙋操作
- if (button.selected) { // 取消举手
- if (self.alertView && self.alertView.isShow) {
- [self.alertView dismissAlertView];
- }
- self.alertView = [KSNormalAlertView ks_showAlertWithTitle:@"确认取消举手吗?" leftTitle:@"取消" rightTitle:@"确认" cancel:^{
-
- } confirm:^{
- [[ClassroomService sharedService] enableDevice:NO withType:DeviceTypeHandup];
- }];
- }
- else {
- if (self.alertView && self.alertView.isShow) {
- [self.alertView dismissAlertView];
- }
- self.alertView = [KSNormalAlertView ks_showAlertWithTitle:@"确认举手吗?" leftTitle:@"取消" rightTitle:@"确认" cancel:^{
-
- } confirm:^{
- [[ClassroomService sharedService] enableDevice:YES withType:DeviceTypeHandup];
- }];
- }
-
- }
- #pragma mark ------ 创建MBProgress
- - (MBProgressHUD *)createProgressHUD {
- [MBProgressHUD hideHUD];
- MBProgressHUD *hud = [MBProgressHUD showHUDAddedTo:self.view animated:YES];
- hud.mode = MBProgressHUDModeIndeterminate;
- hud.contentColor = [UIColor whiteColor];
- hud.bezelView.style = MBProgressHUDBackgroundStyleSolidColor;
- hud.bezelView.backgroundColor = [UIColor colorWithHexString:@"#000000" alpha:0.8];
- [hud hideAnimated:YES afterDelay:60.0f]; // 自动关闭时间60s
- return hud;
- }
- /*
- #pragma mark - Navigation
- // In a storyboard-based application, you will often want to do a little preparation before navigation
- - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
- // Get the new view controller using [segue destinationViewController].
- // Pass the selected object to the new view controller.
- }
- */
- #pragma mark ----- RCRTCEngineEventDelegate
- - (void)didOccurError:(RCRTCCode)errorCode {
- if (errorCode == RCRTCCodeAudioDeviceStartError) {
- // 提示
- [self.tipsView showTipsMessage:@"音频设备启动失败,请尝试重启设备后重新进入" inView:self.view];
- }
- }
- @end
|