BGTPublishController的副本.m 34 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961
  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. // 清晰度定义
  26. #define HD_LEVEL_720P 1 // 1280 * 720
  27. #define HD_LEVEL_540P 2 // 960 * 540
  28. #define HD_LEVEL_360P 3 // 640 * 360
  29. #define HD_LEVEL_360_PLUS 4 // 640 * 360 且开启码率自适应
  30. #define kRePublishTime 3 // 断开后重新尝试的次数
  31. @interface BGTPublishController ()<TXLivePushListener,TXLivePlayListener,TXVideoCustomProcessDelegate,TiUIManagerDelegate,BeautySettingPanelDelegate,AgoraRtcEngineDelegate>{
  32. BeautySettingPanel *_beautyPanel; // 美颜控件
  33. }
  34. /////////////// TiSDK 添加 开始 /////////////
  35. //@property(nonatomic, strong) TiSDKManager *tiSDKManager;
  36. //@property(nonatomic, strong) TiUIView *tiUIView;
  37. /////////////// TiSDK 添加 结束 /////////////
  38. @end
  39. @implementation BGTPublishController
  40. {
  41. //声网dev
  42. BOOL unpublishing;
  43. UIView *userListView;
  44. UIView *userView1;
  45. UIView *userView2;
  46. UIView *userView3;
  47. }
  48. - (void)didReceiveMemoryWarning
  49. {
  50. [super didReceiveMemoryWarning];
  51. }
  52. - (void)endLive
  53. {
  54. [[NSNotificationCenter defaultCenter] removeObserver:self];
  55. [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(startRtmp) object:nil];
  56. }
  57. - (void)dealloc
  58. {
  59. NSLog(@"%s",__func__);
  60. [[NSNotificationCenter defaultCenter] removeObserver:self];
  61. // if (self.tiSDKManager) {
  62. // [self.tiSDKManager destroy];
  63. // self.tiSDKManager = nil;
  64. // }
  65. }
  66. - (void)viewDidLoad
  67. {
  68. [super viewDidLoad];
  69. unpublishing = NO;
  70. ///////////// TiSDK 添加 开始 ////////////
  71. [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onMainSwitchButtonClick:) name:@"onMainSwitchButtonClick" object:nil];
  72. //#error TiSDK Key, 与包名对应,请联系商务获取
  73. NSString* key = [GlobalVariables sharedInstance].appModel.bogo_beauty_key;
  74. if([BGUtils isBlankString:key])
  75. {
  76. //这里写上那个key
  77. key = @"517a990947274dd8b51e1525feb0fb79";
  78. // [[BGHUDHelper sharedInstance] tipMessage:ASLocalizedString(@"美颜key为空,请尝试重新打开app获取!")];
  79. }
  80. else
  81. {
  82. // NSString* key = [GlobalVariables sharedInstance].appModel.bogo_beauty_key;
  83. //
  84. // // NSString* key = @"";
  85. //
  86. //// [[TiSDKManager shareManager] destroy];
  87. //// [[TiUIManager shareManager] destroy]; // TiSDK开源UI窗口对象资源释放
  88. // [TiSDK init:key CallBack:^(InitStatus initStatus) {
  89. // [[NSNotificationCenter defaultCenter] postNotificationName:@"TiSDKInitStatusNotification" object:nil];
  90. // }];
  91. //
  92. // // [[TiUIManager shareManager] loadToSuperview:self.view];
  93. // [TiUIManager shareManager].showsDefaultUI = YES;
  94. // [[TiUIManager shareManager]loadToWindowDelegate:self];
  95. }
  96. [self initConfig];
  97. ///////////// TiSDK 添加 结束 /////////////
  98. //loading imageview
  99. float width = 34;
  100. float height = 34;
  101. float offsetX = (self.view.frame.size.width - width) / 2;
  102. float offsetY = (self.view.frame.size.height - height) / 2;
  103. 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];
  104. _loadingImageView = [[UIImageView alloc] initWithFrame:CGRectMake(offsetX, offsetY, width, height)];
  105. _loadingImageView.animationImages = array;
  106. _loadingImageView.animationDuration = 1;
  107. _loadingImageView.hidden = YES;
  108. [self.view addSubview:_loadingImageView];
  109. }
  110. -(void)onMainSwitchButtonClick:(NSNotificationCenter *)sender{
  111. [[TiUIManager shareManager]showMainMenuView];
  112. _beautyPanel.hidden = NO;
  113. // [self.tiUIView onMainSwitchButtonClick:nil];
  114. }
  115. //声网dev
  116. - (void)initializeAgoraEngine {
  117. self.agoraKit = [AgoraRtcEngineKit sharedEngineWithAppId:[GlobalVariables sharedInstance].appModel.agora_app_id delegate:self];
  118. }
  119. - (void)setChannelProfile {
  120. [self.agoraKit setChannelProfile:AgoraChannelProfileLiveBroadcasting];
  121. }
  122. - (void)setClientRole {
  123. [self.agoraKit setClientRole:AgoraClientRoleBroadcaster];
  124. }
  125. - (void)setupLocalVideo {
  126. // 启用视频模块
  127. [self.agoraKit enableVideo];
  128. AgoraRtcVideoCanvas *videoCanvas = [[AgoraRtcVideoCanvas alloc] init];
  129. videoCanvas.uid = 0;
  130. videoCanvas.renderMode = AgoraVideoRenderModeHidden;
  131. videoCanvas.view = _preViewContainer;
  132. // 设置本地视图
  133. [self.agoraKit setupLocalVideo:videoCanvas];
  134. }
  135. - (void)joinChannel {
  136. // 频道内每个用户的 uid 必须是唯一的
  137. int status = [self.agoraKit joinChannelByToken:self.agora_token channelId:self.roomIDStr info:nil uid:[IMAPlatform sharedInstance].host.userId.intValue joinSuccess:^(NSString * _Nonnull channel, NSUInteger uid, NSInteger elapsed) {
  138. [self startRtmpStreaming:self.pushUrlStr];
  139. NSLog(@"加入声网房间成功");
  140. }];
  141. NSLog(@"声网 status %d",status);
  142. }
  143. -(void)startRtmpStreaming:(NSString *)rtmp
  144. {
  145. [self.agoraKit startRtmpStreamWithTranscoding:rtmp transcoding:[AgoraPushUtils getLiveHostTranscoding:[IMAPlatform sharedInstance].host.userId]];
  146. }
  147. // 远端用户加入频道时,会触发该回调
  148. //- (void)rtcEngine:(AgoraRtcEngineKit *)engine didJoinedOfUid:(NSUInteger)uid elapsed:(NSInteger)elapsed {
  149. //
  150. // userView1.hidden = NO;
  151. // userView2.hidden = YES;
  152. // userView3.hidden = YES;
  153. // [self reloduserListView];
  154. //
  155. //// AgoraRtcVideoCanvas *videoCanvas = [[AgoraRtcVideoCanvas alloc] init];
  156. //// videoCanvas.uid = uid;
  157. //// videoCanvas.renderMode = AgoraVideoRenderModeHidden;
  158. //// videoCanvas.view = userView1;
  159. //// // 设置远端视图
  160. //// [self.agoraKit setupRemoteVideo:videoCanvas];
  161. //
  162. //
  163. //
  164. //}
  165. //
  166. //- (void)rtcEngine:(AgoraRtcEngineKit* _Nonnull)engine didOfflineOfUid:(NSUInteger)uid reason:(AgoraUserOfflineReason)reason NS_SWIFT_NAME(rtcEngine(_:didOfflineOfUid:reason:))
  167. //{
  168. // NSLog(@"用户离开");
  169. //}
  170. //重连操作
  171. - (void)rtcEngine:(AgoraRtcEngineKit* _Nonnull)engine rtmpStreamingChangedToState:(NSString* _Nonnull)url state:(AgoraRtmpStreamingState)state errorCode:(AgoraRtmpStreamingErrorCode)errorCode NS_SWIFT_NAME(rtcEngine(_:rtmpStreamingChangedToState:state:errorCode:)){
  172. NSLog(@"rtmpStreamingChangedToState %lu errorCode %lu",(unsigned long)state,(unsigned long)errorCode);
  173. // if(state == AgoraRtmpStreamingStateFailure)
  174. // {
  175. // if(errorCode != AgoraRtmpStreamingErrorCodeInternalServerError)
  176. // {
  177. // unpublishing = YES;
  178. // [self.agoraKit stopRtmpStream:self.pushUrlStr];
  179. // }
  180. // }
  181. // else if(state == AgoraRtmpStreamingStateIdle)
  182. // {
  183. // if(unpublishing == YES)
  184. // {
  185. // unpublishing = NO;
  186. // [self startRtmpStreaming:self.pushUrlStr];
  187. // }
  188. // }
  189. }
  190. - (void)rtcEngine:(AgoraRtcEngineKit* _Nonnull)engine rtmpStreamingEventWithUrl:(NSString* _Nonnull)url eventCode:(AgoraRtmpStreamingEvent)eventCode NS_SWIFT_NAME(rtcEngine(_:rtmpStreamingEventWithUrl:eventCode:));
  191. {
  192. NSLog(@"rtmpStreamingEventWithUrl %@ eventCode %lu",url,(unsigned long)eventCode);
  193. }
  194. //===
  195. #pragma mark 初始化配置
  196. - (void)initConfig
  197. {
  198. [self.view setBackgroundColor:kBlackColor];
  199. //声网dev
  200. if([GlobalVariables sharedInstance].openAgora == YES)
  201. {
  202. [self initializeAgoraEngine];
  203. [self setChannelProfile];
  204. [self setClientRole];
  205. // [self setupLocalVideo];
  206. }
  207. else
  208. {
  209. _txLivePushonfig = [[TXLivePushConfig alloc] init];
  210. _txLivePushonfig.frontCamera = YES;
  211. _txLivePushonfig.enableAEC = YES;
  212. _txLivePushonfig.enableHWAcceleration = YES;
  213. _txLivePushonfig.enableAutoBitrate = NO;
  214. _txLivePushonfig.audioChannels = 1; // 单声道
  215. GlobalVariables *BuguLive = [GlobalVariables sharedInstance];
  216. // 0:标清(360*640) 1:高清(540*960) 2:超清(720*1280)
  217. if (BuguLive.appModel.video_resolution_type == 0)
  218. {
  219. _txLivePushonfig.videoResolution = VIDEO_RESOLUTION_TYPE_360_640;
  220. _txLivePushonfig.videoBitratePIN = 700;
  221. }
  222. else if (BuguLive.appModel.video_resolution_type == 1)
  223. {
  224. _txLivePushonfig.videoResolution = VIDEO_RESOLUTION_TYPE_540_960;
  225. _txLivePushonfig.videoBitratePIN = 1000;
  226. }
  227. else if (BuguLive.appModel.video_resolution_type == 2)
  228. {
  229. _txLivePushonfig.videoResolution = VIDEO_RESOLUTION_TYPE_720_1280;
  230. _txLivePushonfig.videoBitratePIN = 1500;
  231. }
  232. _txLivePushonfig.autoAdjustStrategy = NO;
  233. _txLivePushonfig.videoFPS = 20;
  234. _txLivePushonfig.audioSampleRate = AUDIO_SAMPLE_RATE_48000; // 不要用其它的
  235. _txLivePushonfig.pauseFps = 10;
  236. _txLivePushonfig.pauseTime = 300;
  237. _txLivePushonfig.pauseImg = [UIImage imageNamed:@"lr_bg_leave.png"];
  238. _txLivePublisher = [[TXLivePush alloc] initWithConfig:_txLivePushonfig];
  239. _txLivePublisher.delegate = self;
  240. // 设置日志级别
  241. [TXLiveBase setLogLevel:LOGLEVEL_NULL];
  242. }
  243. [[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(onPKViewChange:) name:@"onPKViewChange" object:nil];
  244. // 初始化视频父视图
  245. _preViewContainer = [[UIView alloc] initWithFrame:self.view.bounds];
  246. [self.view insertSubview:_preViewContainer atIndex:0];
  247. _preViewContainer.center = self.view.center;
  248. _preViewContainer.backgroundColor = kBlackColor;
  249. //声网dev
  250. if([GlobalVariables sharedInstance].openAgora == YES)
  251. {
  252. [self setupLocalVideo];
  253. int userViewWidth = 80;
  254. int userViewHeight = userViewWidth * 1.5;
  255. userListView = [[UIView alloc] initWithFrame:CGRectMake(kScreenW - userViewWidth - 10, kScreenH - userViewHeight*3 - 60, userViewWidth, userViewHeight*3 + 30)];
  256. [self.view addSubview:userListView];
  257. userView1 = [[UIView alloc] initWithFrame:CGRectMake(0, 0, userViewWidth, userViewHeight)];
  258. userView1.backgroundColor = kRedColor;
  259. [userListView addSubview:userView1];
  260. userView2 = [[UIView alloc] initWithFrame:CGRectMake(0, 0, userViewWidth, userViewHeight)];
  261. userView2.backgroundColor = kYellowColor;
  262. [userListView addSubview:userView2];
  263. userView3 = [[UIView alloc] initWithFrame:CGRectMake(0, 0, userViewWidth, userViewHeight)];
  264. userView3.backgroundColor = kBlueColor;
  265. [userListView addSubview:userView3];
  266. // userView1.hidden = YES;
  267. userView2.hidden = YES;
  268. userView3.hidden = YES;
  269. [self reloduserListView];
  270. // [userListView alignSubviewsVerticallyWithPadding:0 margin:0];
  271. // [userListView gridViews:userListView.subviews inColumn:1 size:CGSizeMake(userViewWidth, userViewHeight) margin:CGSizeMake(0, 0) inRect:CGRectMake(0, 0, userViewWidth, userViewHeight)];
  272. if (_delegate && [_delegate respondsToSelector:@selector(firstIFrame:)])
  273. {
  274. [_delegate firstIFrame:self];
  275. _rePublishTime = 0;
  276. }
  277. }
  278. #if TARGET_IPHONE_SIMULATOR
  279. [self toastTip:ASLocalizedString(@"iOS模拟器不支持推流和播放,请使用真机体验")];
  280. #endif
  281. NSLog(ASLocalizedString(@"==========腾讯SDK版本号:%@"),[TXLiveBase getSDKVersionStr]);
  282. }
  283. -(void)reloduserListView
  284. {
  285. NSArray *subView = userListView.subviews;
  286. for (int i=0; i<subView.count; i++) {
  287. UIView *itemView = subView[i];
  288. [itemView mas_remakeConstraints:^(MASConstraintMaker *make) {
  289. }];
  290. }
  291. NSMutableArray *realViewArr = [NSMutableArray array];
  292. for (int i=0; i<subView.count; i++) {
  293. UIView *itemView = subView[i];
  294. if(itemView.hidden == NO)
  295. {
  296. [realViewArr addObject:itemView];
  297. }
  298. }
  299. int userViewWidth = 80;
  300. int userViewHeight = userViewWidth * 1.5;
  301. [userListView mas_remakeConstraints:^(MASConstraintMaker *make) {
  302. make.width.equalTo(@(userViewWidth));
  303. make.height.equalTo(@(userViewHeight * realViewArr.count));
  304. make.bottom.equalTo(self.view).offset(-80);
  305. make.right.equalTo(self.view).offset(-20);
  306. make.height.equalTo(@(realViewArr.count * userViewHeight));
  307. }];
  308. if(realViewArr.count > 1)
  309. {
  310. [realViewArr mas_makeConstraints:^(MASConstraintMaker *make) {
  311. make.height.equalTo(@(userViewHeight));
  312. make.width.equalTo(@(userViewWidth));
  313. }];
  314. [realViewArr mas_distributeViewsAlongAxis:MASAxisTypeVertical withFixedItemLength:userViewHeight leadSpacing:0 tailSpacing:0];
  315. }
  316. else if(realViewArr.count == 1)
  317. {
  318. [realViewArr[0] mas_makeConstraints:^(MASConstraintMaker *make) {
  319. make.bottom.equalTo(userListView);
  320. make.height.equalTo(@(userViewHeight));
  321. make.width.equalTo(@(userViewWidth));
  322. }];
  323. }
  324. }
  325. - (void)initRightVideoContainerView{
  326. if (!_rightVideoContrainerView) {
  327. _rightVideoContrainerView = [[UIView alloc]initWithFrame:CGRectMake(kScreenW / 2, kStatusBarHeight + 53 + 55, kScreenW / 2, kScreenW * 2 / 3)];
  328. _rightVideoContrainerView.backgroundColor = kClearColor;
  329. }
  330. [self.view addSubview:_rightVideoContrainerView];
  331. }
  332. - (void)initTXLivePlayerWithUrl:(NSString *)playUrl playType:(NSInteger)playType{
  333. if (!_txLivePlayer) {
  334. _txLivePlayer = [[TXLivePlayer alloc] init];//初始化
  335. }
  336. if (!_txLivePlayConfig) {
  337. _txLivePlayConfig = [[TXLivePlayConfig alloc]init];
  338. _txLivePlayConfig.enableAEC = YES;
  339. }
  340. [_txLivePlayer setConfig:_txLivePlayConfig];
  341. _txLivePlayer.delegate = self; //如果您需要处理播放的事件
  342. [_txLivePlayer setupVideoWidget:CGRectMake(0, 0, 0, 0) containView:_rightVideoContrainerView insertIndex:0];
  343. //4-16 2.苹果连麦无法与安卓和苹果之间连麦,对方是没有影子。
  344. int result = [_txLivePlayer startPlay:[NSString stringWithFormat:@"%@%@",playUrl,@""] type:playType];
  345. if (result == -1)
  346. {
  347. [self toastTip:ASLocalizedString(@"非腾讯云链接,若要放开限制请联系腾讯云商务团队")];
  348. }
  349. if( result != 0)
  350. {
  351. NSLog(ASLocalizedString(@"播放器启动失败"));
  352. }
  353. }
  354. //该参数就是发送过来的通知,接到通知后执行的方法
  355. - (void)onPKViewChange:(NSNotification *)notify
  356. {
  357. int isFull = [[notify.userInfo valueForKey:@"isFull"] intValue];
  358. NSString *playUrl = [notify.userInfo valueForKey:@"playUrl"];
  359. TX_Enum_PlayType _playType = PLAY_TYPE_LIVE_RTMP;
  360. if ([playUrl hasPrefix:@"rtmp:"])
  361. {
  362. _playType = PLAY_TYPE_LIVE_RTMP;
  363. }
  364. else if (([playUrl hasPrefix:@"https:"] || [playUrl hasPrefix:@"http:"]) && [playUrl rangeOfString:@".flv"].length > 0)
  365. {
  366. _playType = PLAY_TYPE_LIVE_FLV;
  367. }
  368. if(isFull == 1)
  369. {
  370. //模拟动态修改
  371. _preViewContainer.frame = self.view.bounds;
  372. // [redBgView removeFromSuperview];
  373. // [blueBgView removeFromSuperview];
  374. [pkBgView removeFromSuperview];
  375. _txLivePlayer.delegate = nil;
  376. [_txLivePlayer stopPlay];
  377. [_txLivePlayer removeVideoWidget];
  378. _txLivePlayer = nil;
  379. [_rightVideoContrainerView removeFromSuperview];
  380. _rightVideoContrainerView = nil;
  381. float width = 34;
  382. float height = 34;
  383. float offsetX = (self.view.frame.size.width - width) / 2;
  384. float offsetY = (self.view.frame.size.height - height) / 2;
  385. _loadingImageView.frame = CGRectMake(offsetX, offsetY, width, height);
  386. [_txLivePublisher setVideoQuality:VIDEO_QUALITY_HIGH_DEFINITION adjustBitrate:YES adjustResolution:YES];
  387. [self stopLoadingAnimation];
  388. }
  389. else if(isFull == 3)
  390. {
  391. // _preViewContainer.frame = CGRectMake(0, 0, kScreenW/2, kScreenH/);
  392. _preViewContainer.frame = CGRectMake(0, kStatusBarHeight + 53 + 55, kScreenW / 2, kScreenW * 2 / 3);
  393. [self addPkBgView];
  394. [self initRightVideoContainerView];
  395. [self initTXLivePlayerWithUrl:[self changeRTMPToFlv:playUrl] playType:_playType];
  396. _loadingImageView.centerX = _rightVideoContrainerView.centerX;
  397. _loadingImageView.centerY = _rightVideoContrainerView.centerY;
  398. [_txLivePublisher setVideoQuality:VIDEO_QUALITY_STANDARD_DEFINITION adjustBitrate:YES adjustResolution:YES];
  399. }
  400. else if(isFull == 0)
  401. {
  402. _preViewContainer.frame = CGRectMake(0, kStatusBarHeight + 53 + 55, kScreenW / 2, kScreenW * 2 / 3);
  403. // _preViewContainer.frame = CGRectMake(kScreenW/2, 0, kScreenW/2, kScreenH/2);
  404. [self addPkBgView];
  405. [self initRightVideoContainerView];
  406. [self initTXLivePlayerWithUrl:[self changeRTMPToFlv:playUrl] playType:_playType];
  407. _loadingImageView.centerX = _rightVideoContrainerView.centerX;
  408. _loadingImageView.centerY = _rightVideoContrainerView.centerY;
  409. [_txLivePublisher setVideoQuality:VIDEO_QUALITY_STANDARD_DEFINITION adjustBitrate:YES adjustResolution:YES];
  410. }
  411. }
  412. - (void)addVSView{
  413. //红蓝双方
  414. if (!redBgView) {
  415. redBgView = [[UIView alloc]initWithFrame:CGRectMake(0, 0, kScreenW / 2, kScreenH)];
  416. redBgView.backgroundColor = [UIColor colorWithHexString:@"#731a5a"];
  417. [self.view addSubview:redBgView];
  418. [self.view sendSubviewToBack:redBgView];
  419. }else{
  420. [self.view addSubview:redBgView];
  421. [self.view sendSubviewToBack:redBgView];
  422. }
  423. if (!blueBgView) {
  424. blueBgView = [[UIView alloc]initWithFrame:CGRectMake(kScreenW / 2, 0, kScreenW / 2, kScreenH)];
  425. blueBgView.backgroundColor = [UIColor colorWithHexString:@"#012e89"];
  426. [self.view addSubview:blueBgView];
  427. [self.view sendSubviewToBack:blueBgView];
  428. }else{
  429. [self.view addSubview:blueBgView];
  430. [self.view sendSubviewToBack:blueBgView];
  431. }
  432. }
  433. - (void)addPkBgView{
  434. if (!pkBgView) {
  435. pkBgView = [[UIImageView alloc]initWithFrame:CGRectMake(0, 0, kScreenW, kScreenH)];
  436. pkBgView.image = [UIImage imageNamed:@"pk_bg"];
  437. }
  438. [self.view addSubview:pkBgView];
  439. [self.view sendSubviewToBack:pkBgView];
  440. }
  441. - (void)viewWillDisappear:(BOOL)animated {
  442. [super viewWillDisappear:animated];
  443. if (!self.txLivePublisher.isPublishing) {
  444. [[NSNotificationCenter defaultCenter]removeObserver:self name:@"onPKViewChange" object:nil];
  445. [GlobalVariables sharedInstance].appModel.spear_live = @"0";
  446. // if (self.tiSDKManager) {
  447. // [self.tiSDKManager destroy];
  448. // self.tiSDKManager = nil;
  449. // if(_tiUIView.viewArr != nil)
  450. // for (UIView *sview in _tiUIView.viewArr) {
  451. // [sview removeFromSuperview];
  452. // }
  453. // }
  454. }
  455. }
  456. //6-19 修改-onPKViewChange
  457. -(void)viewWillAppear:(BOOL)animated{
  458. [super viewWillAppear:animated];
  459. [[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(onPKViewChange:) name:@"onPKViewChange" object:nil];
  460. }
  461. - (void)viewDidDisappear:(BOOL)animated{
  462. [super viewDidDisappear:animated];
  463. }
  464. - (void)viewDidAppear:(BOOL)animated
  465. {
  466. [super viewDidAppear:animated];
  467. #if !TARGET_IPHONE_SIMULATOR
  468. //是否有摄像头权限
  469. AVAuthorizationStatus statusVideo = [AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo];
  470. if (statusVideo == AVAuthorizationStatusDenied)
  471. {
  472. [FanweMessage alert:ASLocalizedString(@"获取摄像头权限失败,请前往隐私-相机设置里面打开应用权限")];
  473. return;
  474. }
  475. #endif
  476. }
  477. #pragma mark - ----------------------- 开始、停止推流 -----------------------
  478. #pragma mark 开始推流
  479. - (BOOL)startRtmp
  480. {
  481. _startTime = [[NSDate date]timeIntervalSince1970]*1000;
  482. _lastTime = _startTime;
  483. NSString* rtmpUrl = self.pushUrlStr;
  484. //声网dev
  485. if([GlobalVariables sharedInstance].openAgora == YES)
  486. {
  487. [self joinChannel];
  488. //是否有摄像头权限
  489. AVAuthorizationStatus statusVideo = [AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo];
  490. if (statusVideo == AVAuthorizationStatusDenied)
  491. {
  492. [FanweMessage alert:ASLocalizedString(@"获取摄像头权限失败,请前往隐私-相机设置里面打开应用权限")];
  493. return NO;
  494. }
  495. //是否有麦克风权限
  496. AVAuthorizationStatus statusAudio = [AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeAudio];
  497. if (statusAudio == AVAuthorizationStatusDenied)
  498. {
  499. [FanweMessage alert:ASLocalizedString(@"获取麦克风权限失败,请前往隐私-麦克风设置里面打开应用权限")];
  500. return NO;
  501. }
  502. return YES;
  503. }
  504. //===
  505. if (rtmpUrl.length == 0)
  506. {
  507. rtmpUrl = ASLocalizedString(@"获取推流地址失败");
  508. }
  509. if (!([rtmpUrl hasPrefix:@"rtmp://"] ))
  510. {
  511. [FanweMessage alert:ASLocalizedString(@"推流地址不合法,目前支持rtmp推流!")];
  512. return NO;
  513. }
  514. //是否有摄像头权限
  515. AVAuthorizationStatus statusVideo = [AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo];
  516. if (statusVideo == AVAuthorizationStatusDenied)
  517. {
  518. [FanweMessage alert:ASLocalizedString(@"获取摄像头权限失败,请前往隐私-相机设置里面打开应用权限")];
  519. return NO;
  520. }
  521. //是否有麦克风权限
  522. AVAuthorizationStatus statusAudio = [AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeAudio];
  523. if (statusAudio == AVAuthorizationStatusDenied)
  524. {
  525. [FanweMessage alert:ASLocalizedString(@"获取麦克风权限失败,请前往隐私-麦克风设置里面打开应用权限")];
  526. return NO;
  527. }
  528. if(_txLivePublisher != nil)
  529. {
  530. _txLivePublisher.delegate = self;
  531. if (!_isPreviewing)
  532. {
  533. [_txLivePublisher startPreview:_preViewContainer];
  534. _isPreviewing = YES;
  535. }
  536. if ([_txLivePublisher startPush:rtmpUrl] != 0)
  537. {
  538. NSLog(ASLocalizedString(@"推流器启动失败:%d"),[_txLivePublisher startPush:rtmpUrl]);
  539. return NO;
  540. }
  541. }
  542. _txLivePublisher.videoProcessDelegate = self;
  543. return YES;
  544. }
  545. #pragma mark 停止推流
  546. - (void)stopRtmp
  547. {
  548. //声网dev
  549. [self.agoraKit leaveChannel:nil];
  550. //===
  551. if(_txLivePublisher != nil)
  552. {
  553. _txLivePublisher.delegate = nil;
  554. [_txLivePublisher stopPreview];
  555. _isPreviewing = NO;
  556. [_txLivePublisher stopPush];
  557. }
  558. if (_txLivePlayer != nil)
  559. {
  560. _txLivePlayer.delegate = nil;
  561. [_txLivePlayer stopPlay];
  562. [_txLivePlayer removeVideoWidget];
  563. }
  564. }
  565. #pragma mark - ----------------------- TXLivePushListener代理事件 -----------------------
  566. - (void)onPushEvent:(int)EvtID withParam:(NSDictionary*)param;
  567. {
  568. // NSLog(@"==========PushEvtID1:%d",EvtID);
  569. dispatch_async(dispatch_get_main_queue(), ^{
  570. if (EvtID == PUSH_EVT_PUSH_BEGIN)
  571. {
  572. if (_delegate && [_delegate respondsToSelector:@selector(firstIFrame:)])
  573. {
  574. [_delegate firstIFrame:self];
  575. _rePublishTime = 0;
  576. }
  577. }
  578. else if (EvtID == PUSH_ERR_NET_DISCONNECT)
  579. {
  580. [self stopRtmp];
  581. _rePublishTime ++;
  582. [self performSelector:@selector(startRtmp) withObject:nil afterDelay:3];
  583. }
  584. else if(EvtID == PUSH_WARNING_HW_ACCELERATION_FAIL)
  585. {
  586. _txLivePublisher.config.enableHWAcceleration = false;
  587. }else if (EvtID == PUSH_WARNING_NET_BUSY){
  588. NSLog(ASLocalizedString(@"网络状况不佳:上行带宽太小,上传数据受阻"));
  589. }
  590. });
  591. }
  592. - (void)onNetStatus:(NSDictionary*)param
  593. {
  594. NSDictionary* dict = param;
  595. _qualityDict = param;
  596. dispatch_async(dispatch_get_main_queue(), ^{
  597. int vbitrate = [(NSNumber*)[dict valueForKey:NET_STATUS_VIDEO_BITRATE] intValue];
  598. // int settrate = [(NSNumber*)[dict valueForKey:NET_STATUS_SET_VIDEO_BITRATE] intValue];
  599. _kbpsRecvStr = StringFromInt(vbitrate);
  600. // _kbpsSendStr = StringFromInt(settrate);
  601. });
  602. }
  603. #pragma mark - BeautySettingPanelDelegate
  604. - (void)onSetBeautyStyle:(NSUInteger)beautyStyle beautyLevel:(float)beautyLevel whitenessLevel:(float)whitenessLevel ruddinessLevel:(float)ruddinessLevel {
  605. [_txLivePublisher setBeautyStyle:beautyStyle beautyLevel:beautyLevel whitenessLevel:whitenessLevel ruddinessLevel:ruddinessLevel];
  606. }
  607. - (void)onSetMixLevel:(float)mixLevel {
  608. [_txLivePublisher setSpecialRatio:mixLevel / 10.0];
  609. }
  610. - (void)onSetEyeScaleLevel:(float)eyeScaleLevel {
  611. [_txLivePublisher setEyeScaleLevel:eyeScaleLevel];
  612. }
  613. - (void)onSetFaceScaleLevel:(float)faceScaleLevel {
  614. [_txLivePublisher setFaceScaleLevel:faceScaleLevel];
  615. }
  616. - (void)onSetFaceBeautyLevel:(float)beautyLevel {
  617. }
  618. - (void)onSetFaceVLevel:(float)vLevel {
  619. [_txLivePublisher setFaceVLevel:vLevel];
  620. }
  621. - (void)onSetChinLevel:(float)chinLevel {
  622. [_txLivePublisher setChinLevel:chinLevel];
  623. }
  624. - (void)onSetFaceShortLevel:(float)shortLevel {
  625. [_txLivePublisher setFaceShortLevel:shortLevel];
  626. }
  627. - (void)onSetNoseSlimLevel:(float)slimLevel {
  628. [_txLivePublisher setNoseSlimLevel:slimLevel];
  629. }
  630. - (void)onSetFilter:(UIImage*)filterImage {
  631. [_txLivePublisher setFilter:filterImage];
  632. }
  633. - (void)onSetGreenScreenFile:(NSURL *)file {
  634. [_txLivePublisher setGreenScreenFile:file];
  635. }
  636. - (void)onSelectMotionTmpl:(NSString *)tmplName inDir:(NSString *)tmplDir {
  637. [_txLivePublisher selectMotionTmpl:tmplName inDir:tmplDir];
  638. }
  639. #pragma mark ------------TXLivePlayListener----------
  640. -(void) onPlayEvent:(int)EvtID withParam:(NSDictionary*)param{
  641. switch (EvtID) {
  642. case PLAY_EVT_PLAY_BEGIN:
  643. [self stopLoadingAnimation];
  644. break;
  645. case PLAY_EVT_PLAY_LOADING:
  646. [self startLoadingAnimation];
  647. break;
  648. default:
  649. break;
  650. }
  651. }
  652. - (void)startLoadingAnimation
  653. {
  654. if (_loadingImageView != nil)
  655. {
  656. _loadingImageView.hidden = NO;
  657. [_loadingImageView startAnimating];
  658. }
  659. }
  660. - (void)stopLoadingAnimation
  661. {
  662. if (_loadingImageView != nil)
  663. {
  664. _loadingImageView.hidden = YES;
  665. [_loadingImageView stopAnimating];
  666. }
  667. }
  668. #pragma mark - ----------------------- 摄像头、闪光灯 -----------------------
  669. #pragma mark 开、关闪光灯
  670. - (void)clickTorch:(BOOL)isOpen
  671. {
  672. if (_txLivePublisher)
  673. {
  674. if (![_txLivePublisher toggleTorch:isOpen])
  675. {
  676. [self toastTip:ASLocalizedString(@"闪光灯启动失败")];
  677. }
  678. }
  679. }
  680. #pragma mark 前置后置摄像头切换
  681. - (void)clickCamera:(UIButton*)btn
  682. {
  683. [_txLivePublisher switchCamera];
  684. }
  685. #pragma mark - ----------------------- 定义清晰度 -----------------------
  686. - (void)changeHD:(UIButton*)btn
  687. {
  688. if ([btn.titleLabel.text isEqualToString:@"720p"] && NO == [self isSuitableMachine:7])
  689. {
  690. [FanweMessage alert:ASLocalizedString(@"直播推流")message:ASLocalizedString(@"iphone 6 及以上机型适合开启720p!")isHideTitle:NO destructiveAction:nil];
  691. return;
  692. }
  693. if ([btn.titleLabel.text isEqualToString:@"540p"] && NO == [self isSuitableMachine:5])
  694. {
  695. [FanweMessage alert:ASLocalizedString(@"直播推流")message:ASLocalizedString(@"iphone 5 及以上机型适合开启540p!")isHideTitle:NO destructiveAction:nil];
  696. return;
  697. }
  698. if (_txLivePublisher == nil) return;
  699. if ([btn.titleLabel.text isEqualToString:@"720p"])
  700. {
  701. TXLivePushConfig* _config = _txLivePublisher.config;
  702. _config.videoBitratePIN = 1500;
  703. _config.videoResolution = [self isSuitableMachine:7 ] ? VIDEO_RESOLUTION_TYPE_720_1280 : VIDEO_RESOLUTION_TYPE_540_960;
  704. _config.enableAutoBitrate = NO;
  705. [_txLivePublisher setConfig:_config];
  706. }
  707. else if ([btn.titleLabel.text isEqualToString:@"540p"])
  708. {
  709. TXLivePushConfig* _config = _txLivePublisher.config;
  710. _config.videoBitratePIN = 1000;
  711. _config.videoResolution = [self isSuitableMachine:5 ] ? VIDEO_RESOLUTION_TYPE_540_960 : VIDEO_RESOLUTION_TYPE_360_640;
  712. _config.enableAutoBitrate = NO;
  713. [_txLivePublisher setConfig:_config];
  714. }
  715. else if ([btn.titleLabel.text isEqualToString:@"360p"])
  716. {
  717. TXLivePushConfig* _config = _txLivePublisher.config;
  718. _config.videoBitratePIN = 700;
  719. _config.videoResolution = VIDEO_RESOLUTION_TYPE_360_640;
  720. _config.enableAutoBitrate = NO;
  721. [_txLivePublisher setConfig:_config];
  722. }
  723. else if ([btn.titleLabel.text isEqualToString:@"360+"])
  724. {
  725. TXLivePushConfig* _config = _txLivePublisher.config;
  726. _config.videoBitrateMin = 500;
  727. _config.videoBitrateMax = 1200;
  728. _config.enableAutoBitrate = YES;
  729. _config.videoResolution = VIDEO_RESOLUTION_TYPE_360_640;
  730. [_txLivePublisher setConfig:_config]; // 此模式下设置bitrate无效
  731. }
  732. }
  733. // iphone 6 及以上机型适合开启720p, 否则20帧的帧率可能无法达到, 这种"流畅不足,清晰有余"的效果并不好
  734. - (BOOL)isSuitableMachine:(int)targetPlatNum
  735. {
  736. int mib[2] = {CTL_HW, HW_MACHINE};
  737. size_t len = 0;
  738. char* machine;
  739. sysctl(mib, 2, NULL, &len, NULL, 0);
  740. machine = (char*)malloc(len);
  741. sysctl(mib, 2, machine, &len, NULL, 0);
  742. NSString* platform = [NSString stringWithCString:machine encoding:NSASCIIStringEncoding];
  743. free(machine);
  744. if ([platform length] > 6)
  745. {
  746. NSString * platNum = [NSString stringWithFormat:@"%C", [platform characterAtIndex: 6 ]];
  747. return ([platNum intValue] >= targetPlatNum);
  748. }
  749. else
  750. {
  751. return NO;
  752. }
  753. }
  754. #pragma mark - ----------------------- 自定义Toast -----------------------
  755. /**
  756. @method 获取指定宽度width的字符串在UITextView上的高度
  757. @param textView 待计算的UITextView
  758. @param Width 限制字符串显示区域的宽度
  759. @result float 返回的高度
  760. */
  761. - (float)heightForString:(UITextView *)textView andWidth:(float)width
  762. {
  763. CGSize sizeToFit = [textView sizeThatFits:CGSizeMake(width, MAXFLOAT)];
  764. return sizeToFit.height;
  765. }
  766. - (void)toastTip:(NSString*)toastInfo
  767. {
  768. NSLog(@"======publishtoastInfo:%@",toastInfo);
  769. CGRect frameRC = [[UIScreen mainScreen] bounds];
  770. frameRC.origin.y = frameRC.size.height - 110;
  771. frameRC.size.height -= 110;
  772. __block UITextView * toastView = [[UITextView alloc] init];
  773. toastView.editable = NO;
  774. toastView.selectable = NO;
  775. frameRC.size.height = [self heightForString:toastView andWidth:frameRC.size.width];
  776. toastView.frame = frameRC;
  777. toastView.text = toastInfo;
  778. toastView.backgroundColor = [UIColor whiteColor];
  779. toastView.alpha = 0.5;
  780. [self.view addSubview:toastView];
  781. dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, 2 * NSEC_PER_SEC);
  782. dispatch_after(popTime, dispatch_get_main_queue(), ^(){
  783. [toastView removeFromSuperview];
  784. toastView = nil;
  785. });
  786. }
  787. #pragma mark ---------美颜增加-------------
  788. - (GLuint)onPreProcessTexture:(GLuint)texture width:(CGFloat)width height:(CGFloat)height{
  789. return [[TiSDKManager shareManager] renderTexture2D:texture Width:width Height:height Rotation:CLOCKWISE_0 Mirror:_txLivePublisher.config.frontCamera];
  790. // if (self.tiSDKManager && [self.tiSDKManager renderTexture2D:texture Width:width Height:height Rotation:CLOCKWISE_0 Mirror:NO]) {
  791. // /////////////////// TiFaceSDK 添加 开始 ///////////////////
  792. // return [self.tiSDKManager renderTexture2D:texture Width:width Height:height Rotation:CLOCKWISE_0 Mirror:NO];
  793. // /////////////////// TiFaceSDK 添加 结束 ///////////////////
  794. // }
  795. // return texture;
  796. }
  797. //#pragma mark ---------美颜增加-------------
  798. //- (GLuint)onPreProcessTexture:(GLuint)texture width:(CGFloat)width height:(CGFloat)height{
  799. // if (self.tiSDKManager && [self.tiSDKManager renderTexture2D:texture Width:width Height:height Rotation:CLOCKWISE_0 Mirror:NO]) {
  800. // /////////////////// TiFaceSDK 添加 开始 ///////////////////
  801. // return [self.tiSDKManager renderTexture2D:texture Width:width Height:height Rotation:CLOCKWISE_0 Mirror:NO];
  802. // /////////////////// TiFaceSDK 添加 结束 ///////////////////
  803. // }
  804. // return texture;
  805. //}
  806. //可以在这里释放创建的OpenGL资源
  807. - (void)onTextureDestoryed{
  808. // [self.tiSDKManager destroy];
  809. }
  810. - (NSString *)changeRTMPToFlv:(NSString *)originalString{
  811. NSMutableString *mStr = [NSMutableString stringWithString:originalString];
  812. // [mStr replaceCharactersInRange:NSMakeRange(0, 4) withString:@"http"];
  813. // [mStr appendString:@".flv"];
  814. return mStr;
  815. }
  816. @end