webRtcPlayerViewController.m 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446
  1. //
  2. // webRtcPlayerViewController.m
  3. // 双子星云手机
  4. //
  5. // Created by xd h on 2024/9/2.
  6. //
  7. #import "webRtcPlayerViewController.h"
  8. #import "webRtcPlayerViewController+AdjustBtnFrame.h"
  9. #import "webRtcPlayerViewController+AdjustPlayerViewFrame.h"
  10. #import "UIInterface+HXRotation.h"
  11. #import "playerSetView.h"
  12. @interface webRtcPlayerViewController ()<MediaStreamClientEventsDelegate>
  13. {
  14. BOOL outputVolumeKVO;/*标记声音监听通知*/
  15. }
  16. @property (nonatomic, copy) NSTimer *playerSecondTimer; // 定时器-控制按钮
  17. @end
  18. @implementation webRtcPlayerViewController
  19. @synthesize controlBtn;
  20. - (void)viewDidLoad {
  21. [super viewDidLoad];
  22. // Do any additional setup after loading the view.
  23. [self.toolBar setHidden:YES];
  24. [self.navigationBar setHidden:YES];
  25. [self.navBarBGView setHidden:YES];
  26. [self.view setBackgroundColor:[UIColor blackColor]];
  27. if([DFPlayer sharedPlayer].state == DFPlayerStateBuffering
  28. ||[DFPlayer sharedPlayer].state == DFPlayerStatePlaying){
  29. _isCodeSuspendAudioType = YES;
  30. [[DFPlayer sharedPlayer] df_pause];
  31. }
  32. }
  33. - (void)viewWillAppear:(BOOL)animated {
  34. [super viewWillAppear:animated];
  35. // 屏幕常亮
  36. [UIApplication sharedApplication].idleTimerDisabled = YES;
  37. [[UIApplication sharedApplication] setStatusBarHidden:YES];
  38. }
  39. - (void)viewDidAppear:(BOOL)animated
  40. {
  41. [super viewDidAppear:animated];
  42. [self noEnablePanRightBack];
  43. [self addKVOObserverFun];
  44. ksharedAppDelegate.supportScreenRotateType = YES;
  45. }
  46. - (void)viewDidDisappear:(BOOL)animated{
  47. [super viewDidDisappear:animated];
  48. [_mediaStream disconnect];
  49. [self enablePanRightBack];
  50. [self removeKVOObserverFun];
  51. ksharedAppDelegate.supportScreenRotateType = NO;
  52. }
  53. - (void)setWebRtcMsgMod:(webRtcMsgModel *)webRtcMsgMod
  54. {
  55. _webRtcMsgMod = webRtcMsgMod;
  56. [self beginWebRtcPlayFun];
  57. }
  58. #pragma mark 开始拉流
  59. - (void)beginWebRtcPlayFun
  60. {
  61. _mediaStream = [[RTC_OBJC_TYPE(AMediaStream) alloc] initWithFrame:CGRectZero];
  62. [_mediaStream setEventDelegate:self];
  63. [self.view addSubview:_mediaStream];
  64. [_mediaStream mas_makeConstraints:^(MASConstraintMaker *make) {
  65. make.left.mas_equalTo(0.f);
  66. make.bottom.mas_equalTo(0.f);
  67. make.right.mas_equalTo(0.f);
  68. make.top.mas_equalTo(0.f);
  69. }];
  70. [self linkWebRtcFun];
  71. [self initBaseUIFun];
  72. [self setTimerCountDown];
  73. CGFloat curRate = 1080.0/1920.0;
  74. [self setPoMas_makeWithImageRate:curRate];
  75. [self showNewIndicatorWithCanBack:YES canTouch:NO];
  76. }
  77. #pragma mark 链接webrtc
  78. - (void)linkWebRtcFun
  79. {
  80. //链接用
  81. NSString *signallingUrl = [[NSString alloc] initWithFormat:@"%@:%@",_webRtcMsgMod.data.signalling.domainName,_webRtcMsgMod.data.signalling.port];
  82. NSURL *url = [NSURL URLWithString:signallingUrl];
  83. //ice用
  84. NSString *iceUrl = [[NSString alloc] initWithFormat:@"%@:%@",_webRtcMsgMod.data.turn.domainName,_webRtcMsgMod.data.turn.port];
  85. NSMutableDictionary *ice = [NSMutableDictionary new];
  86. if(iceUrl){
  87. [ice setValue:iceUrl forKey:@"CHINANET"];
  88. [ice setValue:iceUrl forKey:@"CMNET"];
  89. [ice setValue:iceUrl forKey:@"UNICOM"];
  90. }
  91. NSString *roomName = _webRtcMsgMod.data.uniqueIdentifier;
  92. NSInteger result = [_mediaStream start:url
  93. ice:ice
  94. sn:roomName
  95. direct:0
  96. fmt:1//1(h264) 5(h265)
  97. videoWidth:1080.0
  98. videoHeight:1920.0
  99. fps:30
  100. bitrate:3000
  101. cardWidth:0
  102. cardHeight:0
  103. cardDensity:0
  104. token:@"vclusters"];
  105. HLog(@"result:%ld",result)
  106. }
  107. #pragma mark 重连
  108. - (void)relinkWebRtcFun
  109. {
  110. [self linkWebRtcFun];
  111. }
  112. #pragma mark 初始化其他UI
  113. - (void)initBaseUIFun
  114. {
  115. _bottomContrView = [[webRtcPlayerBottomContrView alloc] init];
  116. [self.view addSubview:_bottomContrView];
  117. KWeakSelf
  118. _bottomContrView.didClickButtonFun = ^(NSInteger tag) {
  119. [weakSelf didClickBottomFunBy:tag];
  120. };
  121. /*控制按钮*/
  122. UIImage *driftBtnImage = [UIImage imageNamed:@"you_icon"];
  123. controlBtn = [[UIButton alloc] init];
  124. [controlBtn setBackgroundColor:[UIColor clearColor]];
  125. [controlBtn setBackgroundImage:driftBtnImage forState:(UIControlStateNormal)];
  126. [controlBtn addTarget:self
  127. action:@selector(controlBtnPressed:)
  128. forControlEvents:(UIControlEventTouchUpInside)];
  129. [self.view addSubview:controlBtn];
  130. //拖拽事件等
  131. UIPanGestureRecognizer *gester = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(controlBtnPanGestureCallback:)];
  132. [controlBtn addGestureRecognizer:gester];
  133. //gester.delegate = self;
  134. [self initPointForControlBtnFun];
  135. }
  136. #pragma mark 设置 controlBtn 的初始位置
  137. - (void)initPointForControlBtnFun
  138. {
  139. CGFloat h_w_controlBtn = 60.f;
  140. /*区分横竖屏*/
  141. if (_mediaStream.hw_w > _mediaStream.hw_h){
  142. [controlBtn setFrame:CGRectMake((_mediaStream.hw_w - h_w_controlBtn)/2.f, _mediaStream.hw_h - h_w_controlBtn - 20.f, h_w_controlBtn, h_w_controlBtn)];
  143. }else{
  144. //默认居右
  145. //[mPlayerView.controlBtn setFrame:CGRectMake(mPlayerView.width - h_w_controlBtn - 20.f, (SCREEN_H - h_w_controlBtn)/2.f, h_w_controlBtn, h_w_controlBtn)];
  146. //默认居左
  147. [controlBtn setFrame:CGRectMake( h_w_controlBtn + 10.f, (SCREEN_H - h_w_controlBtn)/2.f, h_w_controlBtn, h_w_controlBtn)];
  148. }
  149. }
  150. #pragma mark 定时器
  151. - (void)setTimerCountDown {
  152. HLog(@"开启一个");
  153. if (_playerSecondTimer) {
  154. // 取消定时器
  155. [_playerSecondTimer invalidate];
  156. _playerSecondTimer = nil;
  157. }
  158. // 初始化值计时数据
  159. //self.adjustTime = 1;
  160. //self.concentTime = [iTools getNowTimeStamp];
  161. _playerSecondTimer = [NSTimer scheduledTimerWithTimeInterval:3.0 target:self selector:@selector(timerChange) userInfo:nil repeats:YES];
  162. [[NSRunLoop currentRunLoop] addTimer:_playerSecondTimer forMode:NSRunLoopCommonModes];
  163. }
  164. #pragma mark 定时器响应事件
  165. - (void)timerChange {
  166. [self extensionAdjustBtnFrameCheckAdjustTime];// 1、悬浮球3s后 自动靠边隐藏
  167. //[self checkConcentTime];// 3、30s之后 没有收到拉流数据 自动断开链接
  168. }
  169. #pragma mark 控制按钮点击事件
  170. - (void)controlBtnPressed:(UIButton*)but
  171. {
  172. playerSetView *nextVC = [[playerSetView alloc] init];
  173. [ksharedAppDelegate.window addSubview:nextVC];
  174. [nextVC mas_makeConstraints:^(MASConstraintMaker *make) {
  175. make.left.mas_equalTo(0);
  176. make.right.mas_equalTo(0);
  177. make.top.mas_equalTo(0.f);
  178. make.bottom.mas_equalTo(0.f);
  179. }];
  180. KWeakSelf
  181. nextVC.didClickButtonFun = ^(NSInteger tag) {
  182. switch (tag) {
  183. case 10:
  184. {//截图
  185. //self->needScreenShotType = YES;
  186. }
  187. break;
  188. #pragma mark 重启盒子
  189. case 11:
  190. {
  191. //[weakSelf didClickRestartFun];
  192. }
  193. break;
  194. case 12:
  195. {//退出云机
  196. [weakSelf exitCloudPhoneFun];
  197. }
  198. break;
  199. case 100:
  200. {
  201. // BOOL fullscreenType = [HWDataManager getBoolWithKey:Consn_player_full_screen_show];
  202. // if(fullscreenType){
  203. // [weakSelf showOpenTVP2PFun];
  204. // }
  205. // else{
  206. // [weakSelf openTvShowFun];
  207. // }
  208. }
  209. break;
  210. case 101:
  211. {
  212. // self->mPlayerView.controlBtn.userInteractionEnabled = NO;
  213. // dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
  214. // self->mPlayerView.controlBtn.userInteractionEnabled = YES;
  215. // });
  216. // [weakSelf showCloseTVP2PFun];
  217. }
  218. break;
  219. default:
  220. break;
  221. }
  222. };
  223. }
  224. #pragma mark 退出云机
  225. - (void)exitCloudPhoneFun
  226. {
  227. //[self setShowImgAndVoiceTypeFun:NO];
  228. if(_isCodeSuspendAudioType){
  229. [[DFPlayer sharedPlayer] df_play];
  230. }
  231. [self.navigationController popViewControllerAnimated:YES];
  232. }
  233. #pragma mark 底部按钮事件
  234. - (void)didClickBottomFunBy:(NSInteger)tag
  235. {
  236. int keyType = 0;
  237. if(tag == 1){//task
  238. keyType = 187;
  239. }
  240. else if(tag == 2){//home
  241. keyType = 3;
  242. }
  243. else if(tag == 3){//back
  244. keyType = 4;
  245. }
  246. if(keyType > 0){
  247. [self didClickKeyEventFunBy:keyType];
  248. }
  249. }
  250. #pragma mark 按键事件
  251. // home 3 back 4 task 187 volumeUp 24 volumeDown 25
  252. - (void)didClickKeyEventFunBy:(int)keyType
  253. {
  254. [_mediaStream sendKey:keyType];
  255. }
  256. #pragma mark -- /*通知添加与移除*/
  257. - (void)addKVOObserverFun
  258. {
  259. outputVolumeKVO = YES;
  260. [[AVAudioSession sharedInstance] addObserver:self forKeyPath:@"outputVolume" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld context:(void *)[AVAudioSession sharedInstance]];
  261. }
  262. - (void)removeKVOObserverFun
  263. {
  264. if (outputVolumeKVO)
  265. {
  266. [[AVAudioSession sharedInstance] removeObserver:self forKeyPath:@"outputVolume" context:(void *)[AVAudioSession sharedInstance]];
  267. outputVolumeKVO = NO;
  268. }
  269. }
  270. #pragma mark 系统音量键监听
  271. - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context{
  272. if(context == (__bridge void *)[AVAudioSession sharedInstance])
  273. {
  274. /*音量开关打开时 允许发送指令 否则直接返回*/
  275. float newValue = [[change objectForKey:@"new"] floatValue];
  276. float oldValue = [[change objectForKey:@"old"] floatValue];
  277. //HLog(@"音量 --old: %f ---new: %f",oldValue,newValue)
  278. if (newValue > oldValue)
  279. {
  280. HLog(@"\n-----音量增加");
  281. [self didClickKeyEventFunBy:24];
  282. }
  283. else
  284. {
  285. HLog(@"\n-----音量降低");
  286. [self didClickKeyEventFunBy:25];
  287. }
  288. }
  289. }
  290. #pragma mark 监听到云机的宽高以及屏幕方向
  291. - (void)handlUIAfterGetCloudPhoneVideoWidth:(int)videoWidth videoHeight:(int)videoHeight rotation:(int)rotation
  292. {
  293. CGFloat curRate = (CGFloat)videoWidth/(CGFloat)videoHeight;
  294. if(lastVideoWHRate == curRate){
  295. return;
  296. }
  297. didAdjusBtnType = NO;
  298. if(rotation == 0){//竖屏
  299. //切换到竖屏
  300. isLan = NO;
  301. [self hx_rotateToInterfaceOrientation:UIInterfaceOrientationPortrait];
  302. [self setPoMas_makeWithImageRate:curRate];
  303. }
  304. else if(rotation == 1){//横屏
  305. //切换到横屏屏
  306. isLan = YES;
  307. [self hx_rotateToInterfaceOrientation:UIInterfaceOrientationLandscapeRight];
  308. [self setLanMas_makeWithImageRate:curRate];
  309. }
  310. dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
  311. [self extensionAdjustBtnFrameCheckAdjustTime];
  312. });
  313. }
  314. #pragma mark WebRTC 回调 MediaStreamClientEventsDelegate
  315. #pragma mark - 宽高变化
  316. -(void)onFrameResolutionChangedFromPeerName:(NSString*)peerName videoWidth:(int)videoWidth videoHeight:(int)videoHeight rotation:(int)rotation {
  317. HLog(@"peerName:%@---%d---%d--%d",peerName,videoWidth,videoHeight,rotation)
  318. mainBlock(^{
  319. [self handlUIAfterGetCloudPhoneVideoWidth:videoWidth videoHeight:videoHeight rotation:rotation];
  320. });
  321. }
  322. //code 0 成功 1失败
  323. -(void)onAuthResultFromPeerName:(NSString*)peerName code:(int)code descriptions:(NSString*)descriptions
  324. {
  325. HLog(@"onAuthResultFromPeerName:%@---%d---%@",peerName,code,descriptions)
  326. }
  327. #pragma mark 链接发生变化
  328. -(void)onChangeConnectionStateFromPeerName:(NSString*)peerName didChangeIceConnectionState:(RTCIceConnectionState)state
  329. {
  330. HLog(@"onChangeConnectionStateFromPeerName: state:%ld",state)
  331. switch (state) {
  332. case RTCIceConnectionStateConnected:{
  333. //链接成功
  334. mainBlock(^{
  335. [self removeNewIndicator];
  336. });
  337. }
  338. break;
  339. case RTCIceConnectionStateCompleted:
  340. //链接完成
  341. break;
  342. case RTCIceConnectionStateFailed:
  343. //链接失败
  344. break;
  345. case RTCIceConnectionStateDisconnected:
  346. //链接断开
  347. [self relinkWebRtcFun];
  348. break;
  349. case RTCIceConnectionStateClosed:
  350. //链接关闭
  351. break;
  352. default:
  353. break;
  354. }
  355. }
  356. - (void)dataChannelDidChangeFromPeerName:(NSString*)peerName State:(RTCDataChannelState)state{
  357. ;
  358. }
  359. //-(void)onIceConnectedFromPeerName:(NSString*)peerName{
  360. // HLog(@"onIceConnectedFromPeerName:%@",peerName);
  361. // mainBlock(^{
  362. // [self removeNewIndicator];
  363. // });
  364. //}
  365. -(void)didGetStats:(NSString*)peerName stats:(RTC_OBJC_TYPE(RTCStatisticsReport) *)stats {
  366. HLog(@"stats:%@",stats);
  367. }
  368. @end