YBTxLinkMicView.m 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593
  1. //
  2. // YBTxLinkMicView.m
  3. // YBVideo
  4. //
  5. // Created by YB007 on 2020/10/15.
  6. // Copyright © 2020 cat. All rights reserved.
  7. //
  8. #import "YBTxLinkMicView.h"
  9. //#import <TXLiteAVSDK_Professional/TXLivePlayListener.h>
  10. //#import <TXLiteAVSDK_Professional/TXLivePlayConfig.h>
  11. //#import <TXLiteAVSDK_Professional/TXLivePlayer.h>
  12. //#import <TXLiteAVSDK_Professional/TXLivePush.h>
  13. #import <CWStatusBarNotification/CWStatusBarNotification.h>
  14. #import "V8HorizontalPickerView.h"
  15. #import <TXLiteAVSDK_Professional/V2TXLivePlayer.h>
  16. #import "YBLiveRTCManager.h"
  17. @interface YBTxLinkMicView()<V2TXLivePusherObserver,V2TXLivePlayerObserver>{
  18. int _linkCount;
  19. BOOL _viewDismiss;
  20. }
  21. @property(nonatomic,strong)CWStatusBarNotification *notification;
  22. @property(nonatomic,strong)UIView *linkSuperView;
  23. @property(nonatomic,strong)UIView *linkPreView;
  24. @property(nonatomic,strong)UIImageView *loadingIV;
  25. @property(nonatomic,strong)UIButton *closeBtn;
  26. @property(nonatomic,strong)V2TXLiveVideoEncoderParam *txLiveVieoParam;
  27. @property(nonatomic,strong)V2TXLivePusher *txLivePusher;
  28. @property(nonatomic,strong)TXAudioEffectManager *audioEffect;
  29. @property(nonatomic, strong)V2TXLivePlayer *txLivePlayer;
  30. @property(nonatomic,strong)NSString *playUrl;
  31. @property(nonatomic,strong)NSString *pushUrl;
  32. @property(nonatomic,assign)BOOL isHostToHost;
  33. @end
  34. @implementation YBTxLinkMicView
  35. +(instancetype)createLinkMicViewOnSuper:(UIView*)superView andHostToHost:(BOOL)isHostToHost;{
  36. YBTxLinkMicView *linkView = [[YBTxLinkMicView alloc]init];
  37. linkView.linkSuperView = superView;
  38. linkView.isHostToHost = isHostToHost;
  39. [superView addSubview:linkView];
  40. [superView sendSubviewToBack:linkView];
  41. /*
  42. [linkView mas_makeConstraints:^(MASConstraintMaker *make) {
  43. make.right.equalTo(superView.mas_right);
  44. if (isHostToHost) {
  45. make.top.equalTo(superView.mas_top).offset(130+statusbarHeight);
  46. make.width.mas_equalTo(_window_width/2);
  47. make.height.mas_equalTo(_window_width*2/3);
  48. }else {
  49. make.bottom.equalTo(superView.mas_bottom).offset(-120-ShowDiff);
  50. make.width.mas_equalTo(100);
  51. make.height.mas_equalTo(150);
  52. }
  53. }];
  54. */
  55. if (isHostToHost) {
  56. linkView.frame = CGRectMake(_window_width/2, 130+statusbarHeight, _window_width/2, _window_width*2/3);
  57. }else {
  58. linkView.frame = CGRectMake(_window_width-100, _window_height-(150+120+ShowDiff), 100, 150);
  59. }
  60. [linkView setUpView];
  61. return linkView;
  62. }
  63. /** 键盘弹起事件: 目前只处理 PK和连麦 的界面相对位置不变*/
  64. -(void)keyBoardNoticeIsShow:(BOOL)isShow andHeight:(CGFloat)height;{
  65. if (_isHostToHost) {
  66. self.top = 130+statusbarHeight+height;
  67. }else {
  68. self.bottom = _window_height-(150+120+ShowDiff)+height;
  69. }
  70. /*
  71. [self mas_remakeConstraints:^(MASConstraintMaker *make) {
  72. make.right.equalTo(_linkSuperView.mas_right);
  73. if (_isHostToHost) {
  74. make.top.equalTo(_linkSuperView.mas_top).offset(130+statusbarHeight+height);
  75. make.width.mas_equalTo(_window_width/2);
  76. make.height.mas_equalTo(_window_width*2/3);
  77. }else {
  78. make.bottom.equalTo(_linkSuperView.mas_bottom).offset(-120-ShowDiff+height);
  79. make.width.mas_equalTo(100);
  80. make.height.mas_equalTo(150);
  81. }
  82. }];
  83. */
  84. }
  85. -(void)setUpView {
  86. _notification = [CWStatusBarNotification new];
  87. _notification.notificationLabelBackgroundColor = [UIColor redColor];
  88. _notification.notificationLabelTextColor = [UIColor whiteColor];
  89. _linkPreView = [[UIView alloc]init];
  90. [self addSubview:_linkPreView];
  91. [_linkPreView mas_makeConstraints:^(MASConstraintMaker *make) {
  92. make.width.height.centerX.centerY.equalTo(self);
  93. }];
  94. _loadingIV = [[UIImageView alloc]init];
  95. _loadingIV.contentMode = UIViewContentModeScaleAspectFit;
  96. [self addSubview:_loadingIV];
  97. [_loadingIV mas_makeConstraints:^(MASConstraintMaker *make) {
  98. make.width.height.centerX.centerY.equalTo(self);
  99. }];
  100. NSMutableArray *m_array = [NSMutableArray array];
  101. for (int i = 0; i < 14; i++) {
  102. [m_array addObject:[UIImage imageNamed:[NSString stringWithFormat:@"loading_image%d.png",i]]];
  103. }
  104. _loadingIV.animationImages = [NSArray arrayWithArray:m_array];
  105. _loadingIV.animationDuration= [m_array count]*0.1;
  106. _loadingIV.animationRepeatCount = MAXFLOAT;
  107. _closeBtn = [UIButton buttonWithType:UIButtonTypeCustom];
  108. [_closeBtn setImage:[UIImage imageNamed:@"连麦-关闭"] forState:0];
  109. [_closeBtn addTarget:self action:@selector(clickCloseBtn) forControlEvents:UIControlEventTouchUpInside];
  110. [self addSubview:_closeBtn];
  111. _closeBtn.hidden = YES;
  112. [_closeBtn mas_makeConstraints:^(MASConstraintMaker *make) {
  113. make.width.height.mas_equalTo(34);
  114. make.top.equalTo(self.mas_top).offset(3);
  115. make.right.equalTo(self.mas_right).offset(-3);
  116. }];
  117. }
  118. - (void)setLinkDic:(NSDictionary *)linkDic {
  119. _linkDic = linkDic;
  120. _playUrl = minstr([linkDic valueForKey:@"playurl"]);
  121. _pushUrl = minstr([linkDic valueForKey:@"pushurl"]);
  122. }
  123. -(void)linkMicShowViewHaveCloseBtn:(BOOL)haveCloseBtn {
  124. [self addNoti];
  125. _closeBtn.hidden = !haveCloseBtn;
  126. [_loadingIV startAnimating];
  127. if ([_linkDic allKeys].count<=0) {
  128. return;
  129. }
  130. _viewDismiss = NO;
  131. if ([_pushUrl isEqual:@"0"]) {
  132. [self txRtmpPlay];
  133. }else {
  134. [self txRtmpPush];
  135. }
  136. }
  137. -(void)addNoti {
  138. NSNotificationCenter *noti = [NSNotificationCenter defaultCenter];
  139. [noti addObserver:self selector:@selector(appactive) name:UIApplicationDidBecomeActiveNotification object:nil];
  140. [noti addObserver:self selector:@selector(appnoactive) name:UIApplicationWillResignActiveNotification object:nil];
  141. }
  142. -(void)appactive {
  143. // if (_txLivePush) {
  144. // [_txLivePush resumePush];
  145. // }
  146. [_txLivePusher resumeVideo];
  147. }
  148. -(void)appnoactive {
  149. [_txLivePusher pauseVideo];
  150. }
  151. -(void)removeNoti {
  152. [[NSNotificationCenter defaultCenter]removeObserver:self];
  153. }
  154. -(void)destroyLoadingIV {
  155. if (_loadingIV) {
  156. [_loadingIV stopAnimating];
  157. [_loadingIV removeFromSuperview];
  158. _loadingIV = nil;
  159. }
  160. }
  161. -(void)clickCloseBtn {
  162. self.linkMicEvent(TxLinkEventType_LinkDisconnect, _linkDic);
  163. [self linkMicViewDismiss];
  164. }
  165. -(void)linkMicViewDismiss{
  166. [self removeNoti];
  167. [self destroyLoadingIV];
  168. _viewDismiss = YES;
  169. if (_txLivePlayer) {
  170. [_txLivePlayer stopPlay];
  171. _txLivePlayer = nil;
  172. }
  173. if (_txLivePusher) {
  174. [_txLivePusher stopPush];
  175. _txLivePusher = nil;
  176. }
  177. [self.subviews makeObjectsPerformSelector:@selector(removeFromSuperview)];
  178. [self removeFromSuperview];
  179. }
  180. #pragma mark - 推流
  181. -(void)txRtmpPush {
  182. //配置推流参数
  183. _txLiveVieoParam = [[V2TXLiveVideoEncoderParam alloc]init];
  184. _txLiveVieoParam.videoResolution =V2TXLiveVideoResolution1280x720;
  185. _txLivePusher = [[V2TXLivePusher alloc]initWithLiveMode:V2TXLiveMode_RTC];
  186. [_txLivePusher setVideoQuality:_txLiveVieoParam];
  187. [_txLivePusher startCamera:YES];
  188. [_txLivePusher startMicrophone];
  189. [_txLivePusher setRenderView:_linkPreView];
  190. [_txLivePusher startPush:_pushUrl];
  191. [_txLivePusher setObserver:self];
  192. [_txLivePusher setEncoderMirror:YES];
  193. TXBeautyManager *beautyManager = [_txLivePusher getBeautyManager];
  194. [beautyManager setBeautyStyle:0];
  195. [beautyManager setBeautyLevel:9];
  196. [beautyManager setWhitenessLevel:3];
  197. [beautyManager setRuddyLevel:0];
  198. }
  199. #pragma mark --RTC推流回调
  200. /**
  201. * 推流器连接状态回调通知
  202. *
  203. * @param status 推流器连接状态 {@link V2TXLivePushStatus}。
  204. * @param msg 连接状态信息。
  205. * @param extraInfo 扩展信息。
  206. */
  207. - (void)onPushStatusUpdate:(V2TXLivePushStatus)status message:(NSString *)msg extraInfo:(NSDictionary *)extraInfo;
  208. {
  209. dispatch_async(dispatch_get_main_queue(), ^{
  210. if (status == V2TXLivePushStatusDisconnected) {
  211. /// 与服务器断开连接
  212. NSLog(@"movieplay连麦推流 推流失败,结束连麦");
  213. [_notification displayNotificationWithMessage:YZMsg(@"推流失败,结束连麦") forDuration:5];
  214. if (self.linkMicEvent) {
  215. self.linkMicEvent(TxLinkEventType_StopPush, @{});
  216. }
  217. }else if(status == V2TXLivePushStatusConnecting){
  218. /// 正在连接服务器
  219. }else if(status == V2TXLivePushStatusConnectSuccess){
  220. /// 连接服务器成功
  221. NSLog(@"play_linkmic连麦推流已经与服务器握手完毕,开始推流");
  222. if (self.linkMicEvent) {
  223. self.linkMicEvent(TxLinkEventType_StartPush, @{});
  224. }
  225. [self destroyLoadingIV];
  226. }else if(status == V2TXLivePushStatusConnectSuccess){
  227. /// 重连服务器中
  228. [_notification displayNotificationWithMessage:@"网络断连, 已启动自动重连" forDuration:5];
  229. }
  230. });
  231. }
  232. /**
  233. * 推流器连接状态回调通知
  234. *
  235. * @param status 推流器连接状态 {@link V2TXLivePushStatus}。
  236. * @param msg 连接状态信息。
  237. * @param extraInfo 扩展信息。
  238. */
  239. -(void)ybRTCPushStatusUpdate:(V2TXLivePushStatus)status message:(NSString *)msg extraInfo:(NSDictionary *)extraInfo{
  240. dispatch_async(dispatch_get_main_queue(), ^{
  241. if (status == V2TXLivePushStatusDisconnected) {
  242. /// 与服务器断开连接
  243. NSLog(@"movieplay连麦推流 推流失败,结束连麦");
  244. [_notification displayNotificationWithMessage:YZMsg(@"推流失败,结束连麦") forDuration:5];
  245. if (self.linkMicEvent) {
  246. self.linkMicEvent(TxLinkEventType_StopPush, @{});
  247. }
  248. }else if(status == V2TXLivePushStatusConnecting){
  249. /// 正在连接服务器
  250. }else if(status == V2TXLivePushStatusConnectSuccess){
  251. /// 连接服务器成功
  252. NSLog(@"play_linkmic连麦推流已经与服务器握手完毕,开始推流");
  253. if (self.linkMicEvent) {
  254. self.linkMicEvent(TxLinkEventType_StartPush, @{});
  255. }
  256. [self destroyLoadingIV];
  257. }
  258. });
  259. }
  260. -(void)ybPushLiveStatus:(V2TXLiveCode)pushStatus
  261. {
  262. if (pushStatus == V2TXLIVE_OK) {
  263. NSLog(@"LIVEBROADCAST --:推流成功、停止推流");
  264. }else if (pushStatus == V2TXLIVE_ERROR_INVALID_PARAMETER){
  265. [_notification displayNotificationWithMessage:@"操作失败,url 不合法" forDuration:5];
  266. NSLog(@"推流器启动失败");
  267. }else if (pushStatus == V2TXLIVE_ERROR_INVALID_LICENSE){
  268. [_notification displayNotificationWithMessage:@"操作失败,license 不合法,鉴权失败" forDuration:5];
  269. NSLog(@"推流器启动失败");
  270. }else if (pushStatus == V2TXLIVE_ERROR_REFUSED){
  271. [_notification displayNotificationWithMessage:@"操作失败,RTC 不支持同一设备上同时推拉同一个 StreamId" forDuration:5];
  272. NSLog(@"推流器启动失败");
  273. }else if (pushStatus == V2TXLIVE_WARNING_NETWORK_BUSY){
  274. [_notification displayNotificationWithMessage:YZMsg(@"您当前的网络环境不佳,请尽快更换网络保证正常连麦") forDuration:5];
  275. }
  276. }
  277. #pragma mark - 播流
  278. -(void)txRtmpPlay {
  279. [self.txLivePlayer setRenderView:self];
  280. V2TXLiveCode result = [self.txLivePlayer startLivePlay:_playUrl];
  281. NSLog(@"wangminxin%ld",result);
  282. if( result == 0){
  283. NSLog(@"播放视频");
  284. // [loadingImage removeFromSuperview];
  285. // loadingImage = nil;
  286. }
  287. [[UIApplication sharedApplication] setIdleTimerDisabled:YES];
  288. }
  289. #pragma mark -播放监听事件 liveplayObserver
  290. - (void)onError:(id<V2TXLivePlayer>)player code:(V2TXLiveCode)code message:(NSString *)msg extraInfo:(NSDictionary *)extraInfo;
  291. {
  292. NSLog(@"liveplay-error");
  293. [self clickCloseBtn];
  294. }
  295. - (void)onWarning:(id<V2TXLivePlayer>)player code:(V2TXLiveCode)code message:(NSString *)msg extraInfo:(NSDictionary *)extraInfo;
  296. {
  297. NSLog(@"liveplay-onWarning");
  298. }
  299. /**
  300. * 已经成功连接到服务器
  301. *
  302. * @param player 回调该通知的播放器对象。
  303. * @param extraInfo 扩展信息。
  304. */
  305. - (void)onVideoPlaying:(id<V2TXLivePlayer>)player firstPlay:(BOOL)firstPlay extraInfo:(NSDictionary *)extraInfo;
  306. {
  307. [self destroyLoadingIV];
  308. }
  309. -(void)linkMicMixStream:(NSDictionary *)mixStreamDic andHostToHost:(BOOL)isHostToHost{
  310. self.isHostToHost = isHostToHost;
  311. NSString *selfUrl = minstr([mixStreamDic valueForKey:@"selfUrl"]);
  312. NSString *otherUrl = minstr([mixStreamDic valueForKey:@"otherUrl"]);
  313. NSString * mainStreamId = [self getStreamIDByStreamUrl:selfUrl];
  314. NSString *subStreamId = [self getStreamIDByStreamUrl:otherUrl];
  315. V2TXLiveTranscodingConfig *config = [[V2TXLiveTranscodingConfig alloc] init];
  316. config.videoWidth = 540;
  317. config.videoHeight = 960;
  318. config.videoBitrate = 0;
  319. config.videoFramerate = 20;
  320. V2TXLiveMixStream *mainStream = [[V2TXLiveMixStream alloc] init];
  321. V2TXLiveMixStream *subStream = [[V2TXLiveMixStream alloc] init];
  322. if (![PublicObj checkNull:otherUrl]) {
  323. if (isHostToHost) {
  324. config.videoWidth = _window_width;
  325. config.videoHeight = _window_width*2/3;
  326. mainStream.streamId = nil;
  327. mainStream.userId = [Config getOwnID];
  328. mainStream.x = 0;
  329. mainStream.y = 0;
  330. mainStream.height = _window_width*2/3;
  331. mainStream.width = _window_width/2;
  332. mainStream.zOrder = 0;
  333. mainStream.inputType = V2TXLiveMixInputTypeAudioVideo;
  334. subStream.streamId = subStreamId;
  335. subStream.userId = minstr([_linkDic valueForKey:@"userid"]);
  336. subStream.height = _window_width*2/3;
  337. subStream.width = _window_width/2;
  338. subStream.x = _window_width/2;//rr
  339. subStream.y = 0;
  340. subStream.zOrder = 1;
  341. subStream.inputType = V2TXLiveMixInputTypeAudioVideo;
  342. }else{
  343. mainStream.streamId = nil;
  344. mainStream.userId = [Config getOwnID];
  345. mainStream.height = 960;//rrrr
  346. mainStream.width = 540;//rrrr
  347. mainStream.x = 0;
  348. mainStream.y = 0;
  349. mainStream.zOrder = 1;
  350. mainStream.inputType = V2TXLiveMixInputTypeAudioVideo;
  351. subStream.streamId = subStreamId;
  352. subStream.userId = minstr([_linkDic valueForKey:@"userid"]);
  353. subStream.height = 240;
  354. subStream.width = 135;
  355. subStream.x = 390;
  356. subStream.y =576;
  357. subStream.zOrder = 2;
  358. subStream.inputType = V2TXLiveMixInputTypeAudioVideo;
  359. }
  360. config.mixStreams = @[mainStream,subStream];
  361. [[YBLiveRTCManager shareInstance]MixTranscoding:config];
  362. }else{
  363. //断开连麦取消云端混流
  364. [[YBLiveRTCManager shareInstance]MixTranscoding:nil];
  365. }
  366. // NSMutableArray * inputStreamList = [NSMutableArray new];
  367. //
  368. // /**
  369. // * 大背景
  370. // * 主播与主播连麦 背景设置为画布(input_type = 3)
  371. // * 用户-主播连麦大主播fram 或者 主播-主播连麦的背景画布 的fram
  372. // */
  373. // CGFloat big_bg_x = 0;
  374. // CGFloat big_bg_y = 0;
  375. // CGFloat big_bg_w = _window_width;
  376. // CGFloat big_bg_h = _window_height;
  377. //
  378. // /**
  379. // * 视频流
  380. // * 用户-主播连麦连麦用户fram 或者 主播-主播连麦的右边主播fram
  381. // */
  382. // CGFloat small_x = 0.75;//_window_width-100;
  383. // CGFloat small_y = 0.6;//_window_height - 110 -statusbarHeight - 150 -ShowDiff;
  384. // CGFloat small_w = 0.25;//100;
  385. // CGFloat small_h = 0.21;//150;
  386. //
  387. // /**
  388. // * 视频流
  389. // * 仅用于主播与主播连麦,主播-主播左边主播fram
  390. // */
  391. // CGFloat host_own_x = 0;
  392. // CGFloat host_own_y = 0.25;//0
  393. // CGFloat host_own_w = 0.5;//_window_width/2;
  394. // CGFloat host_own_h = 0.5;//_window_width*2/3;
  395. //
  396. // NSString * _mainStreamId = [self getStreamIDByStreamUrl:selfUrl];
  397. // NSString *host_own_stram_id = _mainStreamId;
  398. // NSInteger inputType = 0;
  399. // if (isHostToHost && ![PublicObj checkNull:otherUrl]) {
  400. // host_own_stram_id = @"canvas1";
  401. // inputType = 3;
  402. // // big_bg_x = 0;
  403. // // big_bg_y = 130+statusbarHeight;
  404. // // big_bg_w = host_own_w*2;
  405. // // big_bg_h = host_own_h;
  406. //
  407. // small_x = 0.5;//_window_width/2;
  408. // small_y = 0.25;//host_own_y;
  409. // small_w = 0.5;//host_own_w;
  410. // small_h = 0.5;//host_own_h;
  411. // }
  412. //
  413. // //大主播
  414. // NSDictionary * mainStream = @{
  415. // @"InputStreamName": host_own_stram_id,
  416. // @"LayoutParams": @{
  417. // @"ImageLayer": [NSNumber numberWithInt:1],
  418. // @"ImageWidth": [NSNumber numberWithFloat: big_bg_w],
  419. // @"ImageHeight": [NSNumber numberWithFloat: big_bg_h],
  420. // @"LocationX": [NSNumber numberWithFloat:big_bg_x],
  421. // @"LocationY": [NSNumber numberWithFloat:big_bg_y],
  422. // @"InputType": @(inputType),
  423. // },
  424. // };
  425. // [inputStreamList addObject:mainStream];
  426. //
  427. // if (![PublicObj checkNull:otherUrl]) {
  428. // if (isHostToHost) {
  429. // //pk主播(左边边主播)
  430. // NSDictionary * mainStreamss = @{
  431. // @"InputStreamName": _mainStreamId,
  432. // @"LayoutParams": @{
  433. // @"ImageLayer": [NSNumber numberWithInt:3],
  434. // @"ImageWidth": [NSNumber numberWithFloat: host_own_w],
  435. // @"ImageHeight": [NSNumber numberWithFloat: host_own_h],
  436. // @"LocationX": [NSNumber numberWithFloat:host_own_x],
  437. // @"LocationY": [NSNumber numberWithFloat:host_own_y]
  438. // },
  439. // };
  440. // [inputStreamList addObject:mainStreamss];
  441. // }
  442. // //小主播(用户:右下角) 或者 pk主播(右边主播)
  443. // NSString *subPath = [self getStreamIDByStreamUrl:otherUrl];
  444. // NSDictionary * subStream = @{
  445. // @"InputStreamName": subPath,
  446. // @"LayoutParams": @{
  447. // @"ImageLayer": [NSNumber numberWithInt:2],
  448. // @"ImageWidth": [NSNumber numberWithFloat: small_w],
  449. // @"ImageHeight": [NSNumber numberWithFloat: small_h],
  450. // @"LocationX": [NSNumber numberWithFloat:small_x],
  451. // @"LocationY": [NSNumber numberWithFloat:small_y],
  452. // },
  453. // };
  454. // [inputStreamList addObject:subStream];
  455. // }
  456. //
  457. // //para
  458. // NSDictionary * mergeParams = @{
  459. // @"MixStreamSessionId": _mainStreamId,
  460. // @"OutputParams": @{@"OutputStreamName":_mainStreamId},
  461. // @"InputStreamList": inputStreamList
  462. // };
  463. // NSString *jsonStr = [self pictureArrayToJSON:mergeParams];
  464. //
  465. // NSString *linkUrl = @"Linkmic.MergeVideoStream";
  466. // NSDictionary *mergeInfo = @{
  467. // @"uid":[Config getOwnID],
  468. // @"mergeparams":jsonStr
  469. // };
  470. // NSLog(@"=====json:%@",mergeInfo);
  471. // [self requestLink:mergeInfo andUrl:linkUrl];
  472. }
  473. - (NSString *)pictureArrayToJSON:(NSDictionary *)picArr {
  474. NSData *data=[NSJSONSerialization dataWithJSONObject:picArr options:NSJSONWritingPrettyPrinted error:nil];
  475. NSString *jsonStr=[[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding];
  476. jsonStr = [jsonStr stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
  477. jsonStr = [jsonStr stringByReplacingOccurrencesOfString:@" " withString:@""];
  478. jsonStr = [jsonStr stringByReplacingOccurrencesOfString:@"\n" withString:@""];
  479. NSLog(@"jsonStr==%@",jsonStr);
  480. return jsonStr;
  481. }
  482. -(void)requestLink:(NSDictionary *)dicInfo andUrl:(NSString *)urlStr{
  483. YBWeakSelf;
  484. if (_viewDismiss) {
  485. return;
  486. }
  487. [YBNetworking postWithUrl:urlStr Dic:dicInfo Suc:^(int code, id info, NSString *msg) {
  488. NSLog(@"混流====:%@",info);
  489. if (code != 0 ) {
  490. if (_linkCount > 5) {
  491. return;
  492. }else{
  493. _linkCount ++;
  494. dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
  495. [weakSelf requestLink:dicInfo andUrl:urlStr];
  496. });
  497. }
  498. }
  499. } Fail:^(id fail) {
  500. }];
  501. }
  502. -(NSString*) getStreamIDByStreamUrl:(NSString*) strStreamUrl {
  503. if (strStreamUrl == nil || strStreamUrl.length == 0) {
  504. return nil;
  505. }
  506. strStreamUrl = [strStreamUrl lowercaseString];
  507. //推流地址格式:rtmp://8888.livepush.myqcloud.com/live/8888_test_12345_test?txSecret=aaaa&txTime=bbbb
  508. NSString * strLive = @"/play/";
  509. NSRange range = [strStreamUrl rangeOfString:strLive];
  510. if (range.location == NSNotFound) {
  511. return nil;
  512. }
  513. NSString * strSubString = [strStreamUrl substringFromIndex:range.location + range.length];
  514. NSArray * array = [strSubString componentsSeparatedByCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:@"?."]];
  515. if ([array count] > 0) {
  516. return [array objectAtIndex:0];
  517. }
  518. return @"";
  519. }
  520. //主播-用户连麦上报信息
  521. -(void)linkMicUploadInfo:(NSDictionary *)uploadDic; {
  522. [YBNetworking postWithUrl:@"Live.showVideo" Dic:uploadDic Suc:^(int code, id info, NSString *msg) {
  523. NSLog(@"Live.showVideo:%@",info);
  524. } Fail:^(id fail) {
  525. }];
  526. }
  527. -(V2TXLivePlayer *)txLivePlayer{
  528. if(!_txLivePlayer){
  529. _txLivePlayer = [[V2TXLivePlayer alloc] init];
  530. [_txLivePlayer setObserver:self];
  531. [_txLivePlayer enableObserveAudioFrame:YES];
  532. [_txLivePlayer setRenderFillMode:V2TXLiveFillModeFill];
  533. }
  534. return _txLivePlayer;
  535. }
  536. @end