BGTPublishController.m 58 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623
  1. //
  2. // BGTPublishController.m
  3. // BuguLive
  4. //
  5. // Created by xfg on 16/12/5.
  6. // Copyright © 2016年 xfg. All rights reserved.
  7. //
  8. #import "BGTPublishController.h"
  9. #import <Foundation/Foundation.h>
  10. #import <TXLiteAVSDK_Professional/TXLiveSDKTypeDef.h>
  11. #import <TXLiteAVSDK_Professional/TXLiveBase.h>
  12. //#import <TXLiteAVSDK_Professional/COSClient.h>
  13. #import <sys/types.h>
  14. #import <sys/sysctl.h>
  15. #import <UIKit/UIKit.h>
  16. #import <mach/mach.h>
  17. /////////////////// TiFaceSDK 添加 开始 ///////////////////
  18. #import "TiSDKInterface.h"
  19. //#import "TiUIView.h"
  20. #import "BeautySettingPanel.h"
  21. /////////////////// TiFaceSDK 添加 结束 ///////////////////
  22. //声网dev
  23. #import "AgoraPushUtils.h"
  24. #import "UIView+CustomAutoLayout.h"
  25. #import "BogoPkProgressModel.h"
  26. // 清晰度定义
  27. #define HD_LEVEL_720P 1 // 1280 * 720
  28. #define HD_LEVEL_540P 2 // 960 * 540
  29. #define HD_LEVEL_360P 3 // 640 * 360
  30. #define HD_LEVEL_360_PLUS 4 // 640 * 360 且开启码率自适应
  31. #define kRePublishTime 3 // 断开后重新尝试的次数
  32. #import "UserView.h"
  33. //语音连麦
  34. #import "VoiceLianmaiView.h"
  35. #import "VoiceLianmaiUserModel.h"
  36. @interface BGTPublishController ()<TXLivePushListener,TXLivePlayListener,TXVideoCustomProcessDelegate,TiUIManagerDelegate,BeautySettingPanelDelegate,UserViewDelegate,TRTCCloudDelegate>{
  37. BeautySettingPanel *_beautyPanel; // 美颜控件
  38. }
  39. /////////////// TiSDK 添加 开始 /////////////
  40. //@property(nonatomic, strong) TiSDKManager *tiSDKManager;
  41. //@property(nonatomic, strong) TiUIView *tiUIView;
  42. /////////////// TiSDK 添加 结束 /////////////
  43. @property (nonatomic,copy) NSString * txTaskId;
  44. @end
  45. @implementation BGTPublishController
  46. {
  47. //声网dev
  48. BOOL unpublishing;
  49. UIView *userListView;
  50. UserView *userView1;
  51. UserView *userView2;
  52. UserView *userView3;
  53. NSMutableArray <NSString *> *lianMaiuser;
  54. NSMutableArray <NSString *> *linkedUsers;//已经连接的用户
  55. NSString *PKRtmpURL;
  56. //是否已经混流了
  57. BOOL _isMix;
  58. }
  59. - (TRTCCloud *)trtcCloud {
  60. return [TRTCCloud sharedInstance];
  61. }
  62. - (void)endLive
  63. {
  64. [[NSNotificationCenter defaultCenter] removeObserver:self];
  65. [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(startPushRtmpLiveMethod) object:nil];
  66. }
  67. - (void)dealloc
  68. {
  69. NSLog(@"%s",__func__);
  70. [[NSNotificationCenter defaultCenter] removeObserver:self];
  71. // if (self.tiSDKManager) {
  72. // [self.tiSDKManager destroy];
  73. // self.tiSDKManager = nil;
  74. // }
  75. }
  76. - (void)clickUserView:(UserView *)view
  77. {
  78. }
  79. - (void)clickCloseBtn:(UserView *)view
  80. {
  81. // view.uid
  82. //是否断开连麦
  83. }
  84. - (void)viewDidLoad
  85. {
  86. [super viewDidLoad];
  87. unpublishing = NO;
  88. ///////////// TiSDK 添加 开始 ////////////
  89. lianMaiuser = [NSMutableArray array];
  90. linkedUsers = [NSMutableArray array];
  91. [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onMainSwitchButtonClick:) name:@"onMainSwitchButtonClick" object:nil];
  92. //#error TiSDK Key, 与包名对应,请联系商务获取
  93. NSString* key = [GlobalVariables sharedInstance].appModel.bogo_beauty_key;
  94. if([BGUtils isBlankString:key])
  95. {
  96. //这里写上那个key
  97. key = @"517a990947274dd8b51e1525feb0fb79";
  98. // [[BGHUDHelper sharedInstance] tipMessage:ASLocalizedString(@"美颜key为空,请尝试重新打开app获取!")];
  99. }
  100. else
  101. {
  102. // NSString* key = [GlobalVariables sharedInstance].appModel.bogo_beauty_key;
  103. //
  104. // // NSString* key = @"";
  105. //
  106. //// [[TiSDKManager shareManager] destroy];
  107. //// [[TiUIManager shareManager] destroy]; // TiSDK开源UI窗口对象资源释放
  108. // [TiSDK init:key CallBack:^(InitStatus initStatus) {
  109. // [[NSNotificationCenter defaultCenter] postNotificationName:@"TiSDKInitStatusNotification" object:nil];
  110. // }];
  111. //
  112. // // [[TiUIManager shareManager] loadToSuperview:self.view];
  113. // [TiUIManager shareManager].showsDefaultUI = YES;
  114. // [[TiUIManager shareManager]loadToWindowDelegate:self];
  115. }
  116. [self initConfig];
  117. ///////////// TiSDK 添加 结束 /////////////
  118. //loading imageview
  119. float width = 34;
  120. float height = 34;
  121. float offsetX = (self.view.frame.size.width - width) / 2;
  122. float offsetY = (self.view.frame.size.height - height) / 2;
  123. NSMutableArray *array = [[NSMutableArray alloc] initWithObjects:[UIImage imageNamed:@"loading_image0.png"],[UIImage imageNamed:@"loading_image1.png"],[UIImage imageNamed:@"loading_image2.png"],[UIImage imageNamed:@"loading_image3.png"],[UIImage imageNamed:@"loading_image4.png"],[UIImage imageNamed:@"loading_image5.png"],[UIImage imageNamed:@"loading_image6.png"],[UIImage imageNamed:@"loading_image7.png"], nil];
  124. _loadingImageView = [[UIImageView alloc] initWithFrame:CGRectMake(offsetX, offsetY, width, height)];
  125. _loadingImageView.animationImages = array;
  126. _loadingImageView.animationDuration = 1;
  127. _loadingImageView.hidden = YES;
  128. [self.view addSubview:_loadingImageView];
  129. }
  130. -(void)onMainSwitchButtonClick:(NSNotificationCenter *)sender{
  131. [[TiUIManager shareManager]showMainMenuView];
  132. _beautyPanel.hidden = NO;
  133. // [self.tiUIView onMainSwitchButtonClick:nil];
  134. }
  135. - (void)adjustPlayItemVoiceUserList:(NSArray <VoiceLianmaiUserModel * > *)userlist
  136. {
  137. NSLog(@"刷新语音连麦视图");
  138. NSLog(@"%@",userlist);
  139. userView1.hidden = YES;
  140. userView2.hidden = YES;
  141. userView3.hidden = YES;
  142. // NSMutableArray *needAddLianMaiUser = [NSMutableArray array];//需要连麦的列表
  143. // NSMutableArray *needDelLianMaiUser = [NSMutableArray array];//需要删除的列表
  144. //
  145. //
  146. for (int i=0; i<userlist.count; i++) {
  147. if(i == 0)
  148. {
  149. userView1.hidden = NO;
  150. userView1.userName.text = userlist[i].nick_name;
  151. userView1.uid = userlist[i].user_id;
  152. [self.trtcCloud startRemoteView:userView1.uid streamType:TRTCVideoStreamTypeBig view:userView1.videoView];
  153. }
  154. else if(i == 1)
  155. {
  156. userView2.hidden = NO;
  157. userView2.userName.text = userlist[i].nick_name;
  158. userView2.uid = userlist[i].user_id;
  159. TRTCRenderParams *params = [[TRTCRenderParams alloc] init];
  160. // 画面镜像模式
  161. params.mirrorType = TRTCVideoMirrorTypeDisable;
  162. // 画面填充模式
  163. params.fillMode = TRTCVideoFillMode_Fill;
  164. // 画面旋转角度
  165. params.rotation = TRTCVideoRotation_0;
  166. // 设置远端画面的渲染模式
  167. [self.trtcCloud setRemoteRenderParams:userView2.uid streamType:TRTCVideoStreamTypeBig params:params];
  168. [self.trtcCloud startRemoteView:userView1.uid streamType:TRTCVideoStreamTypeBig view:userView2.videoView];
  169. // AgoraRtcVideoCanvas *videoCanvas = [[AgoraRtcVideoCanvas alloc] init];
  170. // videoCanvas.uid = userlist[i].user_id.intValue;
  171. // videoCanvas.renderMode = AgoraVideoRenderModeHidden;
  172. // videoCanvas.view = userView2.videoView;
  173. // [self.agoraKit setupRemoteVideo:videoCanvas];
  174. }
  175. else if(i == 2)
  176. {
  177. userView3.hidden = NO;
  178. userView3.userName.text = userlist[i].nick_name;
  179. userView3.uid = userlist[i].user_id;
  180. TRTCRenderParams *params = [[TRTCRenderParams alloc] init];
  181. // 画面镜像模式
  182. params.mirrorType = TRTCVideoMirrorTypeDisable;
  183. // 画面填充模式
  184. params.fillMode = TRTCVideoFillMode_Fill;
  185. // 画面旋转角度
  186. params.rotation = TRTCVideoRotation_0;
  187. // 设置远端画面的渲染模式
  188. [self.trtcCloud setRemoteRenderParams:userView3.uid streamType:TRTCVideoStreamTypeBig params:params];
  189. [self.trtcCloud startRemoteView:userView1.uid streamType:TRTCVideoStreamTypeBig view:userView3.videoView];
  190. // AgoraRtcVideoCanvas *videoCanvas = [[AgoraRtcVideoCanvas alloc] init];
  191. // videoCanvas.uid = userlist[i].user_id.intValue;
  192. // videoCanvas.renderMode = AgoraVideoRenderModeHidden;
  193. // videoCanvas.view = userView3.videoView;
  194. // [self.agoraKit setupRemoteVideo:videoCanvas];
  195. }
  196. }
  197. if (userlist.count <= 0) {
  198. return;
  199. }
  200. NSArray *subView = userListView.subviews;
  201. // for (int i=0; i<subView.count; i++) {
  202. // UIView *itemView = subView[i];
  203. // [itemView mas_remakeConstraints:^(MASConstraintMaker *make) {
  204. //
  205. // }];
  206. // }
  207. NSMutableArray *realViewArr = [NSMutableArray array];
  208. for (int i=0; i<subView.count; i++) {
  209. UIView *itemView = subView[i];
  210. if(itemView.hidden == NO)
  211. {
  212. [realViewArr addObject:itemView];
  213. }
  214. }
  215. int userViewWidth = 120;
  216. int userViewHeight = userViewWidth * 1.6;
  217. [userListView mas_remakeConstraints:^(MASConstraintMaker *make) {
  218. make.width.equalTo(@(userViewWidth));
  219. make.height.equalTo(@(userViewHeight * realViewArr.count));
  220. make.bottom.equalTo(self.view).offset(-80);
  221. make.right.equalTo(self.view).offset(-20);
  222. make.height.equalTo(@(realViewArr.count * userViewHeight));
  223. }];
  224. if(realViewArr.count > 1)
  225. {
  226. [realViewArr mas_remakeConstraints:^(MASConstraintMaker *make) {
  227. make.height.equalTo(@(userViewHeight));
  228. make.width.equalTo(@(userViewWidth));
  229. }];
  230. [realViewArr mas_distributeViewsAlongAxis:MASAxisTypeVertical withFixedItemLength:userViewHeight leadSpacing:3 tailSpacing:3];
  231. }
  232. else if(realViewArr.count == 1)
  233. {
  234. [realViewArr[0] mas_remakeConstraints:^(MASConstraintMaker *make) {
  235. make.bottom.equalTo(userListView);
  236. make.height.equalTo(@(userViewHeight));
  237. make.width.equalTo(@(userViewWidth));
  238. }];
  239. }
  240. }
  241. - (void)adjustPlayItemAgora:(TLiveMickListModel *)mickListModel;
  242. {
  243. // [lianMaiuser removeObjectAtIndex:removeIndex];
  244. // [lianMaiuser removeAllObjects];
  245. __block BOOL isfind = NO;
  246. NSMutableArray *allUserIds = [NSMutableArray array];
  247. for (int i=0; i<mickListModel.list_lianmai.count; i++) {
  248. //如果之前有了就不处理他了
  249. TLiveMickModel *mickModel = mickListModel.list_lianmai[i];
  250. if(![lianMaiuser containsObject:mickModel.user_id])
  251. {
  252. [lianMaiuser addObject:mickModel.user_id];
  253. isfind = YES;
  254. }
  255. [allUserIds addObject:mickModel.user_id];
  256. }
  257. [lianMaiuser enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
  258. if(![allUserIds containsObject:obj])
  259. {
  260. isfind = YES;
  261. [lianMaiuser removeObject:obj];
  262. }
  263. }];
  264. if(isfind)
  265. {
  266. [self reloduserListView];
  267. }
  268. }
  269. #pragma mark - 初始化
  270. - (void)initializeAgoraEngine {
  271. [self.trtcCloud addDelegate:self];
  272. }
  273. - (void)joinChannel {
  274. // 设置本地画面的预览模式:开启左右镜像,设置画面为填充模式
  275. TRTCRenderParams *param = [[TRTCRenderParams alloc] init];
  276. param.fillMode = TRTCVideoFillMode_Fill;
  277. param.mirrorType = TRTCVideoMirrorTypeAuto;
  278. [self.trtcCloud setLocalRenderParams:param];
  279. // 启动本地摄像头的预览(localCameraVideoView 是用于渲染本地渲染画面的控件)
  280. [self.trtcCloud startLocalPreview:YES view:_preViewContainer];
  281. // 通过 TXDeviceManager 开启自动对焦并将闪光灯打开
  282. TXDeviceManager *manager = [self.trtcCloud getDeviceManager];
  283. if ([manager isAutoFocusEnabled]) {
  284. [manager enableCameraAutoFocus:YES];
  285. }
  286. //开启闪光灯,手电筒
  287. // [manager enableCameraTorch:YES];
  288. // 开启麦克风采集,并设置当前场景为:音乐模式(高保真采集、低音质损失,推荐配合专业声卡使用)
  289. [self.trtcCloud startLocalAudio:TRTCAudioQualityMusic];
  290. TRTCParams *params = [[TRTCParams alloc] init];
  291. // 以字符串房间号为例
  292. params.roomId = self.roomIDStr.intValue;
  293. params.userId = [IMAPlatform sharedInstance].host.userId;
  294. // 从业务后台获取到的 UserSig
  295. params.userSig = [IMALoginParam loadFromLocal].userSig;
  296. // 替换成您的 SDKAppID
  297. params.sdkAppId = TXSDKAppID;
  298. // 根据需要指定用户角色
  299. params.role = TRTCRoleAnchor;
  300. // 根据需要指定场景
  301. [self.trtcCloud enterRoom:params appScene:TRTCAppSceneLIVE];
  302. TRTCVideoEncParam *videoEncParam = [[TRTCVideoEncParam alloc] init];
  303. videoEncParam.videoFps = 24;
  304. videoEncParam.resMode = TRTCVideoResolutionModePortrait;
  305. videoEncParam.videoResolution = TRTCVideoResolution_960_540;
  306. [self.trtcCloud setVideoEncoderParam:videoEncParam];
  307. }
  308. #pragma mark ******************* 腾讯代理方法 *******************
  309. - (void)onEnterRoom:(NSInteger)result {
  310. if (result > 0) {
  311. // result 代表加入房间所消耗的时间(毫秒)
  312. // [self toastTip:@"Enter room succeed!"];
  313. [self startRtmpStreaming:self.pushUrlStr];
  314. } else {
  315. // result 代表进房失败的错误码
  316. dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
  317. NSString *string = [NSString stringWithFormat:@"Enter room failed (%ld)", result];
  318. [self toastTip:string];
  319. });
  320. }
  321. NSLog(@"onEnterRoom result: %ld", (long)result);
  322. AppDelegate.sharedAppDelegate.isEnterLiveVC = YES;
  323. }
  324. //远程静音视频或者音频
  325. - (void)onUserAudioAvailable:(NSString *)userId available:(BOOL)available {
  326. if (available) {
  327. // 发布音频
  328. } else {
  329. // 取消发布音频
  330. }
  331. NSArray *subView = userListView.subviews;
  332. for (int i=0; i<subView.count; i++) {
  333. UserView *itemView = subView[i];
  334. if(itemView.uid == userId)
  335. {
  336. if(available == NO)
  337. {
  338. NSLog(@"%@ 静音",userId);
  339. }
  340. }
  341. }
  342. }
  343. #pragma mark - //功能描述:某远端用户发布/取消了主路视频画面 取消或者开始连麦
  344. - (void)onUserVideoAvailable:(NSString *)userId available:(BOOL)available {
  345. if (available) {
  346. // 发布视频
  347. } else {
  348. // 取消发布视频
  349. }
  350. NSArray *subView = userListView.subviews;
  351. for (int i=0; i<subView.count; i++) {
  352. UserView *itemView = subView[i];
  353. if(itemView.uid == userId)
  354. {
  355. if(available == NO)
  356. {
  357. NSLog(@"%@ 关闭视频",userId);
  358. itemView.muteVideoView.hidden = NO;
  359. // itemView.videoView.hidden = YES;
  360. }
  361. else
  362. {
  363. NSLog(@"%@ 打开视频",userId);
  364. itemView.muteVideoView.hidden = YES;
  365. // itemView.videoView.hidden = NO;
  366. }
  367. }
  368. }
  369. }
  370. //功能描述:有用户加入当前房间
  371. // 远端用户加入频道时,会触发该回调
  372. - (void)onRemoteUserEnterRoom:(NSString *)userId {
  373. NSLog(@"用户加入房间 %@",userId);
  374. //如果正在pk混流pk
  375. #warning 暂时注释,后续确认是否需要
  376. // if(self.pkTranscodin)
  377. // {
  378. // [self startPKRtmpStreaming:PKRtmpURL];
  379. //
  380. // }
  381. // else
  382. {
  383. // [self.agoraKit updateRtmpTranscoding:self.transcoding];
  384. [self updatePublishMediaStream];
  385. }
  386. [self updateUser];
  387. // [lianMaiuser addObject:StringFromInt(uid)];
  388. // [self reloduserListView];
  389. // AgoraRtcVideoCanvas *videoCanvas = [[AgoraRtcVideoCanvas alloc] init];
  390. // videoCanvas.uid = uid;
  391. // videoCanvas.renderMode = AgoraVideoRenderModeHidden;
  392. // videoCanvas.view = userView1;
  393. // // 设置远端视图
  394. // [self.agoraKit setupRemoteVideo:videoCanvas];
  395. }
  396. - (void)updatePublishMediaStream {
  397. // 媒体流发布的目标地址
  398. TRTCPublishTarget* target = [[TRTCPublishTarget alloc] init];
  399. // 目标地址设定为旁路转推到 CDN
  400. target.mode = TRTCPublishMixStreamToCdn;
  401. TRTCPublishCdnUrl* cdnUrl = [[TRTCPublishCdnUrl alloc] init];
  402. // 拼接发布到直播服务商的推流地址(RTMP 格式)
  403. cdnUrl.rtmpUrl = self.pushUrlStr;
  404. // 腾讯云直播推流地址为 true,第三方为 false
  405. cdnUrl.isInternalLine = YES;
  406. NSMutableArray* cdnUrlList = [NSMutableArray array];
  407. // 可以添加多个 CDN 推流地址
  408. [cdnUrlList addObject:cdnUrl];
  409. target.cdnUrlList = cdnUrlList;
  410. [self.trtcCloud updatePublishMediaStream:self.txTaskId publishTarget:target encoderParam:nil mixingConfig:nil];
  411. }
  412. - (void)onRemoteUserLeaveRoom:(NSString *)userId reason:(NSInteger)reason {
  413. // [self.agoraKit updateRtmpTranscoding:self.transcoding];
  414. [self updatePublishMediaStream];
  415. // NSLog(@"用户加入房间");
  416. // int removeIndex = 0;
  417. // BOOL isFind = NO;
  418. // for (int i = 0; i < lianMaiuser.count; i++) {
  419. // if(i == lianMaiuser[i].intValue)
  420. // {
  421. // removeIndex = i;
  422. // isFind = YES;
  423. // }
  424. // }
  425. // if(isFind)
  426. // {
  427. // [lianMaiuser removeObjectAtIndex:removeIndex];
  428. // [self reloduserListView];
  429. // }
  430. NSLog(@"用户离开");
  431. }
  432. //功能描述:请求跨房通话的结果回调
  433. - (void)onConnectOtherRoom:(NSString *)userId errCode:(TXLiteAVError)errCode errMsg:(NSString *)errMsg{
  434. NSLog(@"channelMediaRelayStateDidChange state %ld --error %@",(long)errCode,errMsg);
  435. }
  436. //我们可以让自己的类继承TRTCCloudDelegate,并重载 onError 函数,最后将 this 指针通过 TRTCCCloud 的 delegate 属性设置给 SDK,就可以在当前类中监听来自 SDK 的回调事件了。
  437. // 监听 SDK 的事件,并对“摄像头未被授权”等错误进行日志打印
  438. - (void)onError:(TXLiteAVError)errCode
  439. errMsg:(nullable NSString *)errMsg
  440. extInfo:(nullable NSDictionary *)extInfo {
  441. NSLog(@"onError code: %d message: %@", errCode, errMsg);
  442. if (ERR_CAMERA_NOT_AUTHORIZED == errCode) {
  443. NSString *errorInfo = @"Current application is not authorized to use the camera:";
  444. errorInfo = [errorInfo stringByAppendingString:errMsg];
  445. NSLog(@"腾讯直播报错日志:%@",errorInfo);
  446. [self toastTip:errorInfo];
  447. }
  448. }
  449. // 如果切换角色失败,onSwitchRole 回调的错误码便不是 0
  450. // If switching operation failed, the error code of the 'onSwitchRole' is not zero
  451. - (void)onSwitchRole:(TXLiteAVError)errCode errMsg:(nullable NSString *)errMsg {
  452. if (errCode != 0) {
  453. NSLog(@"Switching operation failed... ");
  454. }
  455. }
  456. //开始发布媒体流的事件回调
  457. - (void)onStartPublishMediaStream:(NSString *)taskId code:(int)code message:(NSString *)message extraInfo:(nullable NSDictionary *)extraInfo {
  458. self.txTaskId = taskId;
  459. }
  460. // 离开房间事件回调
  461. - (void)onExitRoom:(NSInteger)reason {
  462. if (reason == 0) {
  463. NSLog(@"主动调用 exitRoom 退出房间");
  464. } else if (reason == 1) {
  465. NSLog(@"被服务器踢出当前房间");
  466. } else if (reason == 2) {
  467. NSLog(@"当前房间整个被解散");
  468. }
  469. if (self.leaveRoomBlockSuccess) {
  470. self.leaveRoomBlockSuccess();
  471. }
  472. AppDelegate.sharedAppDelegate.isEnterLiveVC = NO;
  473. }
  474. #pragma mark ******************* 腾讯代理方法 end *******************
  475. -(void)startPKRtmpStreaming:(NSString *)rtmp
  476. {
  477. // [self.agoraKit startRtmpStreamWithTranscoding:rtmp transcoding:self.pkTranscodin];
  478. // 功能描述:开始发布媒体流
  479. [self startRtmpStreaming:rtmp];
  480. }
  481. -(void)startRtmpStreaming:(NSString *)rtmp
  482. {
  483. // self.transcoding = [AgoraPushUtils getLiveHostTranscoding:[IMAPlatform sharedInstance].host.userId];
  484. // [self.agoraKit startRtmpStreamWithTranscoding:rtmp transcoding:self.transcoding];
  485. // 媒体流发布的目标地址
  486. TRTCPublishTarget* target = [[TRTCPublishTarget alloc] init];
  487. // 目标地址设定为旁路转推到 CDN
  488. target.mode = TRTCPublishBigStreamToCdn;
  489. TRTCPublishCdnUrl* cdnUrl = [[TRTCPublishCdnUrl alloc] init];
  490. // 拼接发布到直播服务商的推流地址(RTMP 格式)
  491. cdnUrl.rtmpUrl = rtmp;
  492. // 腾讯云直播推流地址为 true,第三方为 false
  493. cdnUrl.isInternalLine = YES;
  494. NSMutableArray* cdnUrlList = [NSMutableArray array];
  495. // 可以添加多个 CDN 推流地址
  496. [cdnUrlList addObject:cdnUrl];
  497. target.cdnUrlList = cdnUrlList;
  498. // 如果需要混流
  499. TRTCStreamMixingConfig *config = [[TRTCStreamMixingConfig alloc] init];
  500. // if (self.mixUserList.count) {
  501. NSMutableArray<TRTCUser *> *userList = [NSMutableArray array];
  502. NSMutableArray<TRTCVideoLayout *> *layoutList = [NSMutableArray array];
  503. // for (int i = 1; i < MIN(self.mixUserList.count, 16); i++) {
  504. // TRTCUser *user = [[TRTCUser alloc] init];
  505. // // 整型房间号为 intRoomId
  506. // user.roomId = self.roomId.intValue;
  507. // user.userId = self.mixUserList[i];
  508. // [userList addObject:user];
  509. //
  510. // TRTCVideoLayout *layout = [[TRTCVideoLayout alloc] init];
  511. // if ([self.mixUserList[i] isEqualToString:self.userId]) {
  512. // // 主播画面布局
  513. // layout.rect = CGRectMake(0, 0, 540, 960);
  514. // layout.zOrder = 0;
  515. // } else {
  516. // // 连麦观众画面布局
  517. // layout.rect = CGRectMake(400, 5 + i * 245, 135, 240);
  518. // layout.zOrder = 1;
  519. // }
  520. // layout.fixedVideoUser = user;
  521. // layout.fixedVideoStreamType = TRTCVideoStreamTypeBig;
  522. // [layoutList addObject:layout];
  523. // }
  524. // 指定转码流中的每一路输入音频的信息
  525. config.audioMixUserList = [userList copy];
  526. // 指定混合画面的中每一路视频画面的位置、大小、图层以及流类型等信息
  527. config.videoLayoutList = [layoutList copy];
  528. #warning 暂时注释,后续确认是否需要
  529. // 开始发布媒体流 不转码
  530. [self.trtcCloud startPublishMediaStream:target encoderParam:nil mixingConfig:nil];
  531. // 开始发布媒体流 转码
  532. // [self.trtcCloud startPublishMediaStream:target encoderParam:encoderParam mixingConfig:nil];
  533. // 开始发布媒体流 转码+混流
  534. // [self.trtcCloud startPublishMediaStream:target encoderParam:encoderParam mixingConfig:config];
  535. }
  536. -(void)updateLianMaiCoin
  537. {
  538. //用户加入
  539. NSMutableDictionary *parmDict = [NSMutableDictionary dictionary];
  540. [parmDict setObject:@"live_multi_room" forKey:@"ctl"];
  541. [parmDict setObject:@"api_mic_list" forKey:@"act"];
  542. [parmDict setObject:[BogoNetwork shareInstance].token forKey:@"token"];
  543. [parmDict setObject:[BogoNetwork shareInstance].uid forKey:@"uid"];
  544. [parmDict setObject:self.roomIDStr forKey:@"video_id"];
  545. [[NetHttpsManager manager] POSTWithParameters:parmDict SuccessBlock:^(NSDictionary *responseJson)
  546. {
  547. FWWeakify(self)
  548. if ([responseJson toInt:@"status"] == 1)
  549. {
  550. NSMutableArray *model_arr = [NSMutableArray array];
  551. NSArray *arr = [responseJson valueForKey:@"list"];
  552. if ([arr isKindOfClass:[NSArray class]]) {
  553. for (NSDictionary *dic in arr) {
  554. VoiceLianmaiUserModel *model =[VoiceLianmaiUserModel mj_objectWithKeyValues: dic];
  555. if(model.user_id.intValue == [BogoNetwork shareInstance].uid.intValue)
  556. {
  557. continue;
  558. }
  559. if(model.user_id.intValue == userView1.uid.intValue)
  560. {
  561. userView1.numberLab.text = model.coin;
  562. }
  563. if(model.user_id.intValue == userView2.uid.intValue)
  564. {
  565. userView2.numberLab.text = model.coin;
  566. }
  567. if(model.user_id.intValue == userView2.uid.intValue)
  568. {
  569. userView3.numberLab.text = model.coin;
  570. }
  571. }
  572. }
  573. }
  574. } FailureBlock:^(NSError *error)
  575. {
  576. }];
  577. }
  578. -(void)updateUser
  579. {
  580. //用户加入
  581. NSMutableDictionary *parmDict = [NSMutableDictionary dictionary];
  582. [parmDict setObject:@"live_multi_room" forKey:@"ctl"];
  583. [parmDict setObject:@"api_mic_list" forKey:@"act"];
  584. [parmDict setObject:[BogoNetwork shareInstance].token forKey:@"token"];
  585. [parmDict setObject:[BogoNetwork shareInstance].uid forKey:@"uid"];
  586. [parmDict setObject:self.roomIDStr forKey:@"video_id"];
  587. [[NetHttpsManager manager] POSTWithParameters:parmDict SuccessBlock:^(NSDictionary *responseJson)
  588. {
  589. FWWeakify(self)
  590. if ([responseJson toInt:@"status"] == 1)
  591. {
  592. NSMutableArray *model_arr = [NSMutableArray array];
  593. NSArray *arr = [responseJson valueForKey:@"list"];
  594. if ([arr isKindOfClass:[NSArray class]]) {
  595. for (NSDictionary *dic in arr) {
  596. VoiceLianmaiUserModel *model =[VoiceLianmaiUserModel mj_objectWithKeyValues: dic];
  597. if(model.user_id.intValue == [BogoNetwork shareInstance].uid.intValue)
  598. {
  599. continue;
  600. }
  601. [model_arr addObject:model];
  602. }
  603. }
  604. [self adjustPlayItemVoiceUserList:model_arr];
  605. [self updateLianMaiCoin];
  606. }
  607. } FailureBlock:^(NSError *error)
  608. {
  609. }];
  610. }
  611. //===
  612. #pragma mark 初始化配置
  613. - (void)initConfig
  614. {
  615. [self.view setBackgroundColor:kBlackColor];
  616. [self initializeAgoraEngine];
  617. [[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(onPKViewChange:) name:@"onPKViewChange" object:nil];
  618. // 初始化视频父视图
  619. _preViewContainer = [[UIView alloc] initWithFrame:self.view.bounds];
  620. [self.view insertSubview:_preViewContainer atIndex:0];
  621. _preViewContainer.center = self.view.center;
  622. _preViewContainer.backgroundColor = kBlackColor;
  623. int userViewWidth = 120;
  624. int userViewHeight = userViewWidth * 1.6;
  625. userListView = [[UIView alloc] initWithFrame:CGRectMake(kScreenW - userViewWidth - 10, kScreenH - userViewHeight*3 - 60, 0, 0)];
  626. userListView.backgroundColor = kClearColor;
  627. // [self.view addSubview:userListView];
  628. [[GlobalVariables sharedInstance].tliveView addSubview:userListView];
  629. userView1 = [UserView getView];
  630. userView1.delegate = self;
  631. userView1.frame = CGRectMake(0, 0, userViewWidth, userViewHeight);
  632. // userView1 = [[UIView alloc] initWithFrame:CGRectMake(0, 0, userViewWidth, userViewHeight)];
  633. userView1.backgroundColor = kRedColor;
  634. [userListView addSubview:userView1];
  635. userView2 = [UserView getView];
  636. userView2.delegate = self;
  637. userView2.frame = CGRectMake(0, 0, userViewWidth, userViewHeight);
  638. userView2.backgroundColor = kYellowColor;
  639. [userListView addSubview:userView2];
  640. userView3 = [UserView getView];
  641. userView3.delegate = self;
  642. userView3.frame = CGRectMake(0, 0, userViewWidth, userViewHeight);
  643. userView1.hidden = YES;
  644. userView2.hidden = YES;
  645. userView3.hidden = YES;
  646. userView1.userInteractionEnabled = YES;
  647. userView2.userInteractionEnabled = YES;
  648. userView3.userInteractionEnabled = YES;
  649. //添加手势
  650. UITapGestureRecognizer * tapGesture1 = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleTapGestureRecognizer:)];
  651. [userView1 addGestureRecognizer:tapGesture1];
  652. //添加手势
  653. UITapGestureRecognizer * tapGesture2 = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleTapGestureRecognizer:)];
  654. [userView2 addGestureRecognizer:tapGesture2];
  655. UITapGestureRecognizer * tapGesture3 = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleTapGestureRecognizer:)];
  656. [userView3 addGestureRecognizer:tapGesture3];
  657. [self reloduserListView];
  658. // [userListView alignSubviewsVerticallyWithPadding:0 margin:0];
  659. // [userListView gridViews:userListView.subviews inColumn:1 size:CGSizeMake(userViewWidth, userViewHeight) margin:CGSizeMake(0, 0) inRect:CGRectMake(0, 0, userViewWidth, userViewHeight)];
  660. if (_delegate && [_delegate respondsToSelector:@selector(firstIFrame:)])
  661. {
  662. [_delegate firstIFrame:self];
  663. _rePublishTime = 0;
  664. }
  665. #if TARGET_IPHONE_SIMULATOR
  666. [self toastTip:ASLocalizedString(@"iOS模拟器不支持推流和播放,请使用真机体验")];
  667. #endif
  668. NSLog(ASLocalizedString(@"==========腾讯SDK版本号:%@"),[TXLiveBase getSDKVersionStr]);
  669. }
  670. - (void)handleTapGestureRecognizer:(UITapGestureRecognizer *)gestureRecognizer {
  671. UserView *view = (UserView*)gestureRecognizer.view;
  672. NSString *uid = view.uid;
  673. NSLog(@"点击 %@",uid);
  674. // if([uid isEqualToString:[IMAPlatform sharedInstance].host.userId])
  675. // {
  676. FDActionSheet *actionSheet = [[FDActionSheet alloc] initWithTitle:@"" message:@""];
  677. [actionSheet addAction:[FDAction actionWithTitle:ASLocalizedString(@"下麦") type:FDActionTypeDefault CallBack:^{
  678. NSMutableDictionary *mDict = [NSMutableDictionary dictionary];
  679. [mDict setObject:@"video" forKey:@"ctl"];
  680. [mDict setObject:@"stop_lianmai" forKey:@"act"];
  681. [mDict setObject:self.roomIDStr forKey:@"room_id"];
  682. [mDict setObject:uid forKey:@"to_user_id"];
  683. [[NetHttpsManager manager] POSTWithParameters:mDict SuccessBlock:^(NSDictionary *responseJson) {
  684. } FailureBlock:^(NSError *error) {
  685. }];
  686. }]];
  687. [actionSheet addAction:[FDAction actionWithTitle:ASLocalizedString(@"关闭麦克风") type:FDActionTypeDefault CallBack:^{
  688. // _lianmaiOpenSound = NO;
  689. NSMutableDictionary *mDict = [NSMutableDictionary dictionary];
  690. [mDict setObject:@"video" forKey:@"ctl"];
  691. [mDict setObject:@"setLinkUserMuteVoiceStatus" forKey:@"act"];
  692. [mDict setObject:self.roomIDStr forKey:@"video_id"];
  693. [mDict setObject:@"1" forKey:@"mute_status"];
  694. [[NetHttpsManager manager] POSTWithParameters:mDict SuccessBlock:^(NSDictionary *responseJson) {
  695. NSDictionary * userInfo = [NSDictionary dictionaryWithObject:uid forKey:@"uid"];
  696. [[NSNotificationCenter defaultCenter] postNotificationName:@"NOTIFY_onMuteUser" object:userInfo userInfo:userInfo];
  697. } FailureBlock:^(NSError *error) {
  698. }];
  699. //view.micbutton.selected NO
  700. // [self.agoraKit enableLocalAudio:view.micbutton.selected];
  701. // view.micbutton.selected = !view.micbutton.selected;
  702. }]];
  703. [actionSheet addAction:[FDAction actionWithTitle:ASLocalizedString(@"取消") type:FDActionTypeCancel CallBack:^{
  704. }]];
  705. [actionSheet show:[UIApplication sharedApplication].keyWindow];
  706. // }
  707. }
  708. -(void)stopLinkMicWithUid:(NSString *)uid
  709. {
  710. }
  711. -(void)reloduserListView
  712. {
  713. //不要动之前的混流逻辑
  714. //删除之前已有的
  715. for (NSString *item in linkedUsers) {
  716. #warning 暂时注释,后续确认是否需要 AgoraPushUtils
  717. // [self.transcoding removeUser:item.intValue];
  718. }
  719. //添加所有
  720. for (int i=0; i<lianMaiuser.count; i++) {
  721. #warning 暂时注释,后续确认是否需要 AgoraPushUtils
  722. // [AgoraPushUtils setLianMaiTranscodingUser:self.transcoding nowNum:i+1 uid:lianMaiuser[i]];
  723. }
  724. // [self.agoraKit updateRtmpTranscoding:self.pushUrlStr transcoding:self.transcoding];
  725. linkedUsers = lianMaiuser;
  726. //延迟两秒更新旁路流
  727. // dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(10.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
  728. // });
  729. }
  730. - (void)initRightVideoContainerView{
  731. if (!_rightVideoContrainerView) {
  732. _rightVideoContrainerView = [[UIView alloc]initWithFrame:CGRectMake(kScreenW / 2, kStatusBarHeight + 53 + 55, kScreenW / 2, kScreenW * 2 / 3)];
  733. _rightVideoContrainerView.backgroundColor = kClearColor;
  734. [self.view addSubview:_rightVideoContrainerView];
  735. }
  736. }
  737. - (void)initTXLivePlayerWithUrl:(NSString *)playUrl playType:(NSInteger)playType{
  738. if([GlobalVariables sharedInstance].openAgora)
  739. {
  740. return;
  741. }
  742. if (!_txLivePlayer) {
  743. _txLivePlayer = [[TXLivePlayer alloc] init];//初始化
  744. }
  745. if (!_txLivePlayConfig) {
  746. _txLivePlayConfig = [[TXLivePlayConfig alloc]init];
  747. _txLivePlayConfig.enableAEC = YES;
  748. }
  749. [_txLivePlayer setConfig:_txLivePlayConfig];
  750. _txLivePlayer.delegate = self; //如果您需要处理播放的事件
  751. [_txLivePlayer setupVideoWidget:CGRectMake(0, 0, 0, 0) containView:_rightVideoContrainerView insertIndex:0];
  752. //4-16 2.苹果连麦无法与安卓和苹果之间连麦,对方是没有影子。
  753. int result = [_txLivePlayer startLivePlay:[NSString stringWithFormat:@"%@%@",playUrl,@""] type:playType];
  754. if (result == -1)
  755. {
  756. [self toastTip:ASLocalizedString(@"非腾讯云链接,若要放开限制请联系腾讯云商务团队")];
  757. }
  758. if( result != 0)
  759. {
  760. NSLog(ASLocalizedString(@"播放器启动失败"));
  761. }
  762. }
  763. #pragma mark - Pk
  764. //该参数就是发送过来的通知,接到通知后执行的方法
  765. - (void)onPKViewChange:(NSNotification *)notify
  766. {
  767. NSLog(@"pk通知来了 = %@",notify);
  768. int isFull = [[notify.userInfo valueForKey:@"isFull"] intValue];
  769. NSString *playUrl = [notify.userInfo valueForKey:@"playUrl"];
  770. TX_Enum_PlayType _playType = PLAY_TYPE_LIVE_RTMP;
  771. if ([playUrl hasPrefix:@"rtmp:"])
  772. {
  773. _playType = PLAY_TYPE_LIVE_RTMP;
  774. }
  775. else if (([playUrl hasPrefix:@"https:"] || [playUrl hasPrefix:@"http:"]) && [playUrl rangeOfString:@".flv"].length > 0)
  776. {
  777. _playType = PLAY_TYPE_LIVE_FLV;
  778. }
  779. if(isFull == 1) {
  780. // self.pkTranscodin = nil;
  781. // [self.agoraKit stopChannelMediaRelay];
  782. //好像有问题,上面代码注释会崩溃
  783. [self.trtcCloud disconnectOtherRoom];
  784. //模拟动态修改
  785. _preViewContainer.frame = self.view.bounds;
  786. // [redBgView removeFromSuperview];
  787. // [blueBgView removeFromSuperview];
  788. [pkBgView removeFromSuperview];
  789. _txLivePlayer.delegate = nil;
  790. [_txLivePlayer stopPlay];
  791. [_txLivePlayer removeVideoWidget];
  792. _txLivePlayer = nil;
  793. [_rightVideoContrainerView removeFromSuperview];
  794. _rightVideoContrainerView = nil;
  795. float width = 34;
  796. float height = 34;
  797. float offsetX = (self.view.frame.size.width - width) / 2;
  798. float offsetY = (self.view.frame.size.height - height) / 2;
  799. _loadingImageView.frame = CGRectMake(offsetX, offsetY, width, height);
  800. [_txLivePublisher setVideoQuality:VIDEO_QUALITY_HIGH_DEFINITION adjustBitrate:YES adjustResolution:YES];
  801. _isMix = NO;
  802. [self stopLoadingAnimation];
  803. return;
  804. }
  805. if(isFull == 3) {
  806. // _preViewContainer.frame = CGRectMake(0, 0, kScreenW/2, kScreenH/);
  807. _preViewContainer.frame = CGRectMake(0, kStatusBarHeight + 53 + 55, kScreenW / 2, kScreenW * 2 / 3);
  808. [self addPkBgView];
  809. [self initRightVideoContainerView];
  810. [self initTXLivePlayerWithUrl:[self changeRTMPToFlv:playUrl] playType:_playType];
  811. _loadingImageView.centerX = _rightVideoContrainerView.centerX;
  812. _loadingImageView.centerY = _rightVideoContrainerView.centerY;
  813. [_txLivePublisher setVideoQuality:VIDEO_QUALITY_STANDARD_DEFINITION adjustBitrate:YES adjustResolution:YES];
  814. if([GlobalVariables sharedInstance].openAgora)
  815. {
  816. NSMutableDictionary *mDict = [NSMutableDictionary dictionary];
  817. [mDict setObject:@"pk_agora" forKey:@"ctl"];
  818. BogoPkProgressModel *model = [notify.userInfo valueForKey:@"model"];
  819. [mDict setObject:@"getPKRTCChannelToken" forKey:@"act"];
  820. [mDict setObject:[NSString stringWithFormat:@"%@",model.id] forKey:@"pk_id"];
  821. [[NetHttpsManager manager] POSTWithParameters:mDict SuccessBlock:^(NSDictionary *responseJson) {
  822. if ([responseJson toInt:@"status"] == 1 || [responseJson toInt:@"status"] == 2) {
  823. //imUserId 是主播自己的id
  824. NSInteger imUserId = [IMAPlatform sharedInstance].host.imUserId.integerValue;
  825. //src_token 是别人要加入我房间的源token
  826. NSString *src_token = responseJson[@"data"][@"agora_token_src"];
  827. //desc_token 是要加入对方房间的token
  828. NSString *desc_token = responseJson[@"data"][@"agora_token_desc"];
  829. #warning 暂时注释,后续确认是否需要
  830. /*
  831. //总体的config
  832. AgoraChannelMediaRelayConfiguration *config = [[AgoraChannelMediaRelayConfiguration alloc] init];
  833. config.sourceInfo = [[AgoraChannelMediaRelayInfo alloc] initWithToken:responseJson[@"data"][@"agora_token_src"]];
  834. config.sourceInfo.uid = 0;
  835. //声明一个sourceInfo ,用我的房间token
  836. config.sourceInfo = [[AgoraChannelMediaRelayInfo alloc] initWithToken:src_token];
  837. //文档说了必须设置成0
  838. // config.sourceInfo.uid = imUserId;
  839. */
  840. //tagget 是对方的roomid,也是频道号
  841. NSString *tagget = @"";
  842. //myromid 是我的房间号也是我的频道id
  843. NSString *myRoomId = @"";
  844. //toEmccUserid 对方主播的id
  845. NSString *toEmccUserid = @"";
  846. NSString *pushUrl;
  847. if(model.emcee_user_id1.intValue == imUserId) {
  848. tagget = model.room_id2;
  849. myRoomId = model.room_id1;
  850. toEmccUserid = model.emcee_user_id2;
  851. pushUrl = model.push_url1;
  852. } else {
  853. toEmccUserid = model.emcee_user_id1;
  854. tagget = model.room_id1;
  855. myRoomId = model.room_id2;
  856. pushUrl = model.push_url2;
  857. }
  858. //开始混流
  859. // int status = [self.agoraKit startChannelMediaRelay:config];
  860. dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
  861. // 需要延迟执行的代码
  862. // [self channelMediaRelayWidthUid:imUserId andSrcToken:src_token andDestToken:desc_token andChannel:tagget];
  863. });
  864. dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
  865. // 需要延迟执行的代码
  866. // AgoraRtcVideoCanvas *videoCanvas = [[AgoraRtcVideoCanvas alloc] init];
  867. // videoCanvas.uid = toEmccUserid.intValue;
  868. // videoCanvas.renderMode = AgoraVideoRenderModeHidden;
  869. // videoCanvas.view = self->_rightVideoContrainerView;
  870. // // 设置远端视图
  871. // [self.agoraKit setupRemoteVideo:videoCanvas];
  872. // 功能描述:请求跨房通话
  873. NSMutableDictionary *jsonDict = [[NSMutableDictionary alloc] init];
  874. // 此处为数字房间号; 数字房间号为 roomId 对方房间ID,对方主播ID
  875. [jsonDict setObject:@(tagget.intValue) forKey:@"roomId"];
  876. [jsonDict setObject:toEmccUserid forKey:@"userId"];
  877. NSData *jsonData = [NSJSONSerialization dataWithJSONObject:jsonDict options:NSJSONWritingPrettyPrinted error:nil];
  878. NSString *jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
  879. [self.trtcCloud connectOtherRoom:jsonString];
  880. TRTCRenderParams *params = [[TRTCRenderParams alloc] init];
  881. // 画面镜像模式
  882. params.mirrorType = TRTCVideoMirrorTypeAuto;
  883. // 画面填充模式
  884. params.fillMode = TRTCVideoFillMode_Fill;
  885. // 画面旋转角度
  886. params.rotation = TRTCVideoRotation_0;
  887. // 设置远端画面的渲染模式
  888. [self.trtcCloud setRemoteRenderParams:toEmccUserid streamType:TRTCVideoStreamTypeBig params:params];
  889. [self.trtcCloud startRemoteView:toEmccUserid streamType:TRTCVideoStreamTypeBig view:self->_rightVideoContrainerView];
  890. });
  891. // [self setPKTranscodingWithId:toEmccUserid];
  892. // NSLog(@"status %d",status);
  893. }
  894. } FailureBlock:^(NSError *error) {
  895. //do nothing;
  896. }];
  897. //跨频道推流
  898. }
  899. return;
  900. }
  901. if(isFull == 0)
  902. {
  903. _preViewContainer.frame = CGRectMake(0, kStatusBarHeight + 53 + 55, kScreenW / 2, kScreenW * 2 / 3);
  904. // _preViewContainer.frame = CGRectMake(kScreenW/2, 0, kScreenW/2, kScreenH/2);
  905. [self addPkBgView];
  906. [self initRightVideoContainerView];
  907. [self initTXLivePlayerWithUrl:[self changeRTMPToFlv:playUrl] playType:_playType];
  908. _loadingImageView.centerX = _rightVideoContrainerView.centerX;
  909. _loadingImageView.centerY = _rightVideoContrainerView.centerY;
  910. [_txLivePublisher setVideoQuality:VIDEO_QUALITY_STANDARD_DEFINITION adjustBitrate:YES adjustResolution:YES];
  911. return;
  912. }
  913. }
  914. -(void)channelMediaRelayWidthUid:(int)uid andSrcToken:(NSString *)srcToken andDestToken:(NSString *)destToken andChannel:(NSString *)channel;
  915. {
  916. //如果不是主播直接退出
  917. // AgoraChannelMediaRelayConfiguration *config = [[AgoraChannelMediaRelayConfiguration alloc] init];
  918. // AgoraChannelMediaRelayInfo *src = [config sourceInfo];
  919. //
  920. //// src.channelName = nil;
  921. // src.uid = 0;
  922. // src.token = srcToken;
  923. //
  924. //
  925. // AgoraChannelMediaRelayInfo *dst = [[AgoraChannelMediaRelayInfo alloc] init];
  926. // dst.channelName = channel;
  927. // dst.uid = uid;
  928. // dst.token = destToken;
  929. //
  930. // [config setDestinationInfo:dst forChannelName:dst.channelName];
  931. if(_isMix == NO)
  932. {
  933. _isMix = YES;
  934. // [self.agoraKit stopChannelMediaRelay];
  935. //功能描述:退出跨房通话
  936. [self.trtcCloud disconnectOtherRoom];
  937. // [self.agoraKit startChannelMediaRelay:config];
  938. // 功能描述:请求跨房通话
  939. NSMutableDictionary *jsonDict = [[NSMutableDictionary alloc] init];
  940. // 此处为字符房间号; 数字房间号为 roomId
  941. [jsonDict setObject:channel forKey:@"roomId"];
  942. [jsonDict setObject:@(uid) forKey:@"userId"];
  943. NSData *jsonData = [NSJSONSerialization dataWithJSONObject:jsonDict options:NSJSONWritingPrettyPrinted error:nil];
  944. NSString *jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
  945. [self.trtcCloud connectOtherRoom:jsonString];
  946. }
  947. }
  948. - (void)addVSView{
  949. //红蓝双方
  950. if (!redBgView) {
  951. redBgView = [[UIView alloc]initWithFrame:CGRectMake(0, 0, kScreenW / 2, kScreenH)];
  952. redBgView.backgroundColor = [UIColor colorWithHexString:@"#731a5a"];
  953. [self.view addSubview:redBgView];
  954. [self.view sendSubviewToBack:redBgView];
  955. }else{
  956. [self.view addSubview:redBgView];
  957. [self.view sendSubviewToBack:redBgView];
  958. }
  959. if (!blueBgView) {
  960. blueBgView = [[UIView alloc]initWithFrame:CGRectMake(kScreenW / 2, 0, kScreenW / 2, kScreenH)];
  961. blueBgView.backgroundColor = [UIColor colorWithHexString:@"#012e89"];
  962. [self.view addSubview:blueBgView];
  963. [self.view sendSubviewToBack:blueBgView];
  964. }else{
  965. [self.view addSubview:blueBgView];
  966. [self.view sendSubviewToBack:blueBgView];
  967. }
  968. }
  969. - (void)addPkBgView{
  970. if (!pkBgView) {
  971. pkBgView = [[UIImageView alloc]initWithFrame:CGRectMake(0, 0, kScreenW, kScreenH)];
  972. pkBgView.image = [UIImage imageNamed:@"pk_bg"];
  973. }
  974. [self.view addSubview:pkBgView];
  975. [self.view sendSubviewToBack:pkBgView];
  976. }
  977. - (void)viewWillDisappear:(BOOL)animated {
  978. [super viewWillDisappear:animated];
  979. if (!self.txLivePublisher.isPublishing) {
  980. [[NSNotificationCenter defaultCenter]removeObserver:self name:@"onPKViewChange" object:nil];
  981. [GlobalVariables sharedInstance].appModel.spear_live = @"0";
  982. // if (self.tiSDKManager) {
  983. // [self.tiSDKManager destroy];
  984. // self.tiSDKManager = nil;
  985. // if(_tiUIView.viewArr != nil)
  986. // for (UIView *sview in _tiUIView.viewArr) {
  987. // [sview removeFromSuperview];
  988. // }
  989. // }
  990. }
  991. }
  992. //6-19 修改-onPKViewChange
  993. -(void)viewWillAppear:(BOOL)animated{
  994. [super viewWillAppear:animated];
  995. // [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onPKViewChange:) name:@"onPKViewChange" object:nil];
  996. }
  997. - (void)viewDidDisappear:(BOOL)animated{
  998. [super viewDidDisappear:animated];
  999. }
  1000. - (void)viewDidAppear:(BOOL)animated
  1001. {
  1002. [super viewDidAppear:animated];
  1003. #if !TARGET_IPHONE_SIMULATOR
  1004. //是否有摄像头权限
  1005. AVAuthorizationStatus statusVideo = [AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo];
  1006. if (statusVideo == AVAuthorizationStatusDenied)
  1007. {
  1008. [FanweMessage alert:ASLocalizedString(@"获取摄像头权限失败,请前往隐私-相机设置里面打开应用权限")];
  1009. return;
  1010. }
  1011. #endif
  1012. }
  1013. #pragma mark - ----------------------- 开始、停止推流 -----------------------
  1014. #pragma mark 开始推流
  1015. - (BOOL)startPushRtmpLiveMethod {
  1016. _startTime = [[NSDate date]timeIntervalSince1970]*1000;
  1017. _lastTime = _startTime;
  1018. NSString* rtmpUrl = self.pushUrlStr;
  1019. [self joinChannel];
  1020. //是否有摄像头权限
  1021. AVAuthorizationStatus statusVideo = [AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo];
  1022. if (statusVideo == AVAuthorizationStatusDenied)
  1023. {
  1024. [FanweMessage alert:ASLocalizedString(@"获取摄像头权限失败,请前往隐私-相机设置里面打开应用权限")];
  1025. return NO;
  1026. }
  1027. //是否有麦克风权限
  1028. AVAuthorizationStatus statusAudio = [AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeAudio];
  1029. if (statusAudio == AVAuthorizationStatusDenied)
  1030. {
  1031. [FanweMessage alert:ASLocalizedString(@"获取麦克风权限失败,请前往隐私-麦克风设置里面打开应用权限")];
  1032. return NO;
  1033. }
  1034. return YES;
  1035. }
  1036. #pragma mark 停止推流
  1037. - (void)stopRtmp {
  1038. if (_txLivePlayer != nil) {
  1039. _txLivePlayer.delegate = nil;
  1040. [_txLivePlayer stopPlay];
  1041. [_txLivePlayer removeVideoWidget];
  1042. }
  1043. }
  1044. #pragma mark - BeautySettingPanelDelegate
  1045. - (void)onSetBeautyStyle:(NSUInteger)beautyStyle beautyLevel:(float)beautyLevel whitenessLevel:(float)whitenessLevel ruddinessLevel:(float)ruddinessLevel {
  1046. [_txLivePublisher setBeautyStyle:beautyStyle beautyLevel:beautyLevel whitenessLevel:whitenessLevel ruddinessLevel:ruddinessLevel];
  1047. }
  1048. - (void)onSetMixLevel:(float)mixLevel {
  1049. [_txLivePublisher setSpecialRatio:mixLevel / 10.0];
  1050. }
  1051. - (void)onSetEyeScaleLevel:(float)eyeScaleLevel {
  1052. [_txLivePublisher setEyeScaleLevel:eyeScaleLevel];
  1053. }
  1054. - (void)onSetFaceScaleLevel:(float)faceScaleLevel {
  1055. [_txLivePublisher setFaceScaleLevel:faceScaleLevel];
  1056. }
  1057. - (void)onSetFaceBeautyLevel:(float)beautyLevel {
  1058. }
  1059. - (void)onSetFaceVLevel:(float)vLevel {
  1060. [_txLivePublisher setFaceVLevel:vLevel];
  1061. }
  1062. - (void)onSetChinLevel:(float)chinLevel {
  1063. [_txLivePublisher setChinLevel:chinLevel];
  1064. }
  1065. - (void)onSetFaceShortLevel:(float)shortLevel {
  1066. [_txLivePublisher setFaceShortLevel:shortLevel];
  1067. }
  1068. - (void)onSetNoseSlimLevel:(float)slimLevel {
  1069. [_txLivePublisher setNoseSlimLevel:slimLevel];
  1070. }
  1071. - (void)onSetFilter:(UIImage*)filterImage {
  1072. [_txLivePublisher setFilter:filterImage];
  1073. }
  1074. - (void)onSetGreenScreenFile:(NSURL *)file {
  1075. [_txLivePublisher setGreenScreenFile:file];
  1076. }
  1077. - (void)onSelectMotionTmpl:(NSString *)tmplName inDir:(NSString *)tmplDir {
  1078. [_txLivePublisher selectMotionTmpl:tmplName inDir:tmplDir];
  1079. }
  1080. #pragma mark ------------TXLivePlayListener----------
  1081. -(void) onPlayEvent:(int)EvtID withParam:(NSDictionary*)param{
  1082. switch (EvtID) {
  1083. case PLAY_EVT_PLAY_BEGIN:
  1084. [self stopLoadingAnimation];
  1085. break;
  1086. case PLAY_EVT_PLAY_LOADING:
  1087. [self startLoadingAnimation];
  1088. break;
  1089. default:
  1090. break;
  1091. }
  1092. }
  1093. - (void)startLoadingAnimation
  1094. {
  1095. if (_loadingImageView != nil)
  1096. {
  1097. _loadingImageView.hidden = NO;
  1098. [_loadingImageView startAnimating];
  1099. }
  1100. }
  1101. - (void)stopLoadingAnimation
  1102. {
  1103. if (_loadingImageView != nil)
  1104. {
  1105. _loadingImageView.hidden = YES;
  1106. [_loadingImageView stopAnimating];
  1107. }
  1108. }
  1109. #pragma mark - ----------------------- 摄像头、闪光灯 -----------------------
  1110. #pragma mark 开、关闪光灯
  1111. - (void)clickTorch:(BOOL)isOpen
  1112. {
  1113. if (_txLivePublisher)
  1114. {
  1115. if (![_txLivePublisher toggleTorch:isOpen])
  1116. {
  1117. [self toastTip:ASLocalizedString(@"闪光灯启动失败")];
  1118. }
  1119. }
  1120. }
  1121. #pragma mark 前置后置摄像头切换
  1122. - (void)clickCamera:(UIButton*)btn
  1123. {
  1124. [_txLivePublisher switchCamera];
  1125. }
  1126. #pragma mark - ----------------------- 定义清晰度 -----------------------
  1127. - (void)changeHD:(UIButton*)btn
  1128. {
  1129. if ([btn.titleLabel.text isEqualToString:@"720p"] && NO == [self isSuitableMachine:7])
  1130. {
  1131. [FanweMessage alert:ASLocalizedString(@"直播推流")message:ASLocalizedString(@"iphone 6 及以上机型适合开启720p!")isHideTitle:NO destructiveAction:nil];
  1132. return;
  1133. }
  1134. if ([btn.titleLabel.text isEqualToString:@"540p"] && NO == [self isSuitableMachine:5])
  1135. {
  1136. [FanweMessage alert:ASLocalizedString(@"直播推流")message:ASLocalizedString(@"iphone 5 及以上机型适合开启540p!")isHideTitle:NO destructiveAction:nil];
  1137. return;
  1138. }
  1139. if (_txLivePublisher == nil) return;
  1140. if ([btn.titleLabel.text isEqualToString:@"720p"])
  1141. {
  1142. TXLivePushConfig* _config = _txLivePublisher.config;
  1143. _config.videoBitratePIN = 1500;
  1144. _config.videoResolution = [self isSuitableMachine:7 ] ? VIDEO_RESOLUTION_TYPE_720_1280 : VIDEO_RESOLUTION_TYPE_540_960;
  1145. _config.enableAutoBitrate = NO;
  1146. [_txLivePublisher setConfig:_config];
  1147. }
  1148. else if ([btn.titleLabel.text isEqualToString:@"540p"])
  1149. {
  1150. TXLivePushConfig* _config = _txLivePublisher.config;
  1151. _config.videoBitratePIN = 1000;
  1152. _config.videoResolution = [self isSuitableMachine:5 ] ? VIDEO_RESOLUTION_TYPE_540_960 : VIDEO_RESOLUTION_TYPE_360_640;
  1153. _config.enableAutoBitrate = NO;
  1154. [_txLivePublisher setConfig:_config];
  1155. }
  1156. else if ([btn.titleLabel.text isEqualToString:@"360p"])
  1157. {
  1158. TXLivePushConfig* _config = _txLivePublisher.config;
  1159. _config.videoBitratePIN = 700;
  1160. _config.videoResolution = VIDEO_RESOLUTION_TYPE_360_640;
  1161. _config.enableAutoBitrate = NO;
  1162. [_txLivePublisher setConfig:_config];
  1163. }
  1164. else if ([btn.titleLabel.text isEqualToString:@"360+"])
  1165. {
  1166. TXLivePushConfig* _config = _txLivePublisher.config;
  1167. _config.videoBitrateMin = 500;
  1168. _config.videoBitrateMax = 1200;
  1169. _config.enableAutoBitrate = YES;
  1170. _config.videoResolution = VIDEO_RESOLUTION_TYPE_360_640;
  1171. [_txLivePublisher setConfig:_config]; // 此模式下设置bitrate无效
  1172. }
  1173. }
  1174. // iphone 6 及以上机型适合开启720p, 否则20帧的帧率可能无法达到, 这种"流畅不足,清晰有余"的效果并不好
  1175. - (BOOL)isSuitableMachine:(int)targetPlatNum
  1176. {
  1177. int mib[2] = {CTL_HW, HW_MACHINE};
  1178. size_t len = 0;
  1179. char* machine;
  1180. sysctl(mib, 2, NULL, &len, NULL, 0);
  1181. machine = (char*)malloc(len);
  1182. sysctl(mib, 2, machine, &len, NULL, 0);
  1183. NSString* platform = [NSString stringWithCString:machine encoding:NSASCIIStringEncoding];
  1184. free(machine);
  1185. if ([platform length] > 6)
  1186. {
  1187. NSString * platNum = [NSString stringWithFormat:@"%C", [platform characterAtIndex: 6 ]];
  1188. return ([platNum intValue] >= targetPlatNum);
  1189. }
  1190. else
  1191. {
  1192. return NO;
  1193. }
  1194. }
  1195. #pragma mark - ----------------------- 自定义Toast -----------------------
  1196. ///**
  1197. // @method 获取指定宽度width的字符串在UITextView上的高度
  1198. // @param textView 待计算的UITextView
  1199. // @param Width 限制字符串显示区域的宽度
  1200. // @result float 返回的高度
  1201. // */
  1202. //- (float)heightForString:(UITextView *)textView andWidth:(float)width
  1203. //{
  1204. // CGSize sizeToFit = [textView sizeThatFits:CGSizeMake(width, MAXFLOAT)];
  1205. // return sizeToFit.height;
  1206. //}
  1207. - (void)toastTip:(NSString*)toastInfo
  1208. {
  1209. NSLog(@"======publishtoastInfo:%@",toastInfo);
  1210. [QMUITips showWithText:toastInfo];
  1211. // CGRect frameRC = [[UIScreen mainScreen] bounds];
  1212. // frameRC.origin.y = frameRC.size.height - 110;
  1213. // frameRC.size.height -= 110;
  1214. // __block UITextView * toastView = [[UITextView alloc] init];
  1215. //
  1216. // toastView.editable = NO;
  1217. // toastView.selectable = NO;
  1218. //
  1219. // frameRC.size.height = [self heightForString:toastView andWidth:frameRC.size.width];
  1220. //
  1221. // toastView.frame = frameRC;
  1222. //
  1223. // toastView.text = toastInfo;
  1224. // toastView.backgroundColor = [UIColor whiteColor];
  1225. // toastView.alpha = 0.5;
  1226. //
  1227. // [self.view addSubview:toastView];
  1228. //
  1229. // dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, 2 * NSEC_PER_SEC);
  1230. //
  1231. // dispatch_after(popTime, dispatch_get_main_queue(), ^(){
  1232. // [toastView removeFromSuperview];
  1233. // toastView = nil;
  1234. // });
  1235. }
  1236. #pragma mark ---------美颜增加-------------
  1237. //隐藏美颜
  1238. /*
  1239. - (GLuint)onPreProcessTexture:(GLuint)texture width:(CGFloat)width height:(CGFloat)height{
  1240. return [[TiSDKManager shareManager] renderTexture2D:texture Width:width Height:height Rotation:CLOCKWISE_0 Mirror:_txLivePublisher.config.frontCamera];
  1241. // if (self.tiSDKManager && [self.tiSDKManager renderTexture2D:texture Width:width Height:height Rotation:CLOCKWISE_0 Mirror:NO]) {
  1242. // /////////////////// TiFaceSDK 添加 开始 ///////////////////
  1243. // return [self.tiSDKManager renderTexture2D:texture Width:width Height:height Rotation:CLOCKWISE_0 Mirror:NO];
  1244. // /////////////////// TiFaceSDK 添加 结束 ///////////////////
  1245. // }
  1246. // return texture;
  1247. }*/
  1248. //#pragma mark ---------美颜增加-------------
  1249. //- (GLuint)onPreProcessTexture:(GLuint)texture width:(CGFloat)width height:(CGFloat)height{
  1250. // if (self.tiSDKManager && [self.tiSDKManager renderTexture2D:texture Width:width Height:height Rotation:CLOCKWISE_0 Mirror:NO]) {
  1251. // /////////////////// TiFaceSDK 添加 开始 ///////////////////
  1252. // return [self.tiSDKManager renderTexture2D:texture Width:width Height:height Rotation:CLOCKWISE_0 Mirror:NO];
  1253. // /////////////////// TiFaceSDK 添加 结束 ///////////////////
  1254. // }
  1255. // return texture;
  1256. //}
  1257. //可以在这里释放创建的OpenGL资源
  1258. - (void)onTextureDestoryed{
  1259. // [self.tiSDKManager destroy];
  1260. }
  1261. - (NSString *)changeRTMPToFlv:(NSString *)originalString{
  1262. NSMutableString *mStr = [NSMutableString stringWithString:originalString];
  1263. // [mStr replaceCharactersInRange:NSMakeRange(0, 4) withString:@"http"];
  1264. // [mStr appendString:@".flv"];
  1265. return mStr;
  1266. }
  1267. //功能描述:音量大小的反馈回调
  1268. //SDK 可以评估每一路音频的音量大小,并每隔一段时间抛出该事件回调,您可以根据音量大小在 UI 上做出相应的提示,比如 波形图 或 音量槽 。 要完成这个功能, 您需要先调用 enableAudioVolumeEvaluation 开启这个能力并设定事件抛出的时间间隔。 需要补充说明的是,无论当前房间中是否有人说话,SDK 都会按照您设定的时间间隔定时抛出此事件回调。
  1269. - (void)onUserVoiceVolume:(NSArray<TRTCVolumeInfo *> *)userVolumes totalVolume:(NSInteger)totalVolume {
  1270. //totalVolume
  1271. NSLog(@"totalVolume");
  1272. NSLog(@"%ld",totalVolume);
  1273. /*bug:当a用户在麦上正在说话时,切换到无网状态,此时虽然还显示在麦上(im还没下线),
  1274. 但观众席听不到声音,光圈还在闪烁
  1275. 原因: 这时观众席speakers 里面找不到a,就不会进入for循环,就不会更新a的声音为0
  1276. 解决: 1先找到 麦上的用户 2去判断有无声音
  1277. */
  1278. for (TRTCVolumeInfo *info in userVolumes) {
  1279. // for (AgoraRtcAudioVolumeInfo *speaker in speakers) {
  1280. NSString *uid = @"";
  1281. if (info.userId.intValue == 0) {
  1282. uid = [IMAPlatform sharedInstance].host.userId;
  1283. }else{
  1284. uid = [NSString stringWithFormat:@"%@",info.userId];
  1285. }
  1286. if([[userView1 uid] isEqualToString:uid])
  1287. {
  1288. userView1.totalVolume = info.volume;
  1289. }
  1290. if([[userView2 uid] isEqualToString:uid])
  1291. {
  1292. userView2.totalVolume = info.volume;
  1293. }
  1294. if([[userView3 uid] isEqualToString:uid])
  1295. {
  1296. userView3.totalVolume = info.volume;
  1297. }
  1298. //speaker.volume
  1299. }
  1300. if(userVolumes.count == 0)
  1301. {
  1302. userView1.totalVolume = 0;
  1303. userView2.totalVolume = 0;
  1304. userView3.totalVolume = 0;
  1305. }
  1306. // [self.uiController.micView setUsers:self.users];
  1307. }
  1308. @end