// // webRtcPlayerViewController.m // 双子星云手机 // // Created by xd h on 2024/9/2. // #import "webRtcPlayerViewController.h" #import "webRtcPlayerViewController+AdjustBtnFrame.h" #import "webRtcPlayerViewController+AdjustPlayerViewFrame.h" #import "UIInterface+HXRotation.h" #import "playerSetView.h" @interface webRtcPlayerViewController () { BOOL outputVolumeKVO;/*标记声音监听通知*/ } @property (nonatomic, copy) NSTimer *playerSecondTimer; // 定时器-控制按钮 @end @implementation webRtcPlayerViewController @synthesize controlBtn; - (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view. [self.toolBar setHidden:YES]; [self.navigationBar setHidden:YES]; [self.navBarBGView setHidden:YES]; [self.view setBackgroundColor:[UIColor blackColor]]; if([DFPlayer sharedPlayer].state == DFPlayerStateBuffering ||[DFPlayer sharedPlayer].state == DFPlayerStatePlaying){ _isCodeSuspendAudioType = YES; [[DFPlayer sharedPlayer] df_pause]; } } - (void)viewWillAppear:(BOOL)animated { [super viewWillAppear:animated]; // 屏幕常亮 [UIApplication sharedApplication].idleTimerDisabled = YES; [[UIApplication sharedApplication] setStatusBarHidden:YES]; } - (void)viewDidAppear:(BOOL)animated { [super viewDidAppear:animated]; [self noEnablePanRightBack]; [self addKVOObserverFun]; ksharedAppDelegate.supportScreenRotateType = YES; } - (void)viewDidDisappear:(BOOL)animated{ [super viewDidDisappear:animated]; [_mediaStream disconnect]; [self enablePanRightBack]; [self removeKVOObserverFun]; ksharedAppDelegate.supportScreenRotateType = NO; } - (void)setWebRtcMsgMod:(webRtcMsgModel *)webRtcMsgMod { _webRtcMsgMod = webRtcMsgMod; [self beginWebRtcPlayFun]; } #pragma mark 开始拉流 - (void)beginWebRtcPlayFun { _mediaStream = [[RTC_OBJC_TYPE(AMediaStream) alloc] initWithFrame:CGRectZero]; [_mediaStream setEventDelegate:self]; [self.view addSubview:_mediaStream]; [_mediaStream mas_makeConstraints:^(MASConstraintMaker *make) { make.left.mas_equalTo(0.f); make.bottom.mas_equalTo(0.f); make.right.mas_equalTo(0.f); make.top.mas_equalTo(0.f); }]; [self linkWebRtcFun]; [self initBaseUIFun]; [self setTimerCountDown]; CGFloat curRate = 1080.0/1920.0; [self setPoMas_makeWithImageRate:curRate]; [self showNewIndicatorWithCanBack:YES canTouch:NO]; } #pragma mark 链接webrtc - (void)linkWebRtcFun { //链接用 NSString *signallingUrl = [[NSString alloc] initWithFormat:@"%@:%@",_webRtcMsgMod.data.signalling.domainName,_webRtcMsgMod.data.signalling.port]; NSURL *url = [NSURL URLWithString:signallingUrl]; //ice用 NSString *iceUrl = [[NSString alloc] initWithFormat:@"%@:%@",_webRtcMsgMod.data.turn.domainName,_webRtcMsgMod.data.turn.port]; NSMutableDictionary *ice = [NSMutableDictionary new]; if(iceUrl){ [ice setValue:iceUrl forKey:@"CHINANET"]; [ice setValue:iceUrl forKey:@"CMNET"]; [ice setValue:iceUrl forKey:@"UNICOM"]; } NSString *roomName = _webRtcMsgMod.data.uniqueIdentifier; NSInteger result = [_mediaStream start:url ice:ice sn:roomName direct:0 fmt:1//1(h264) 5(h265) videoWidth:1080.0 videoHeight:1920.0 fps:30 bitrate:3000 cardWidth:0 cardHeight:0 cardDensity:0 token:@"vclusters"]; HLog(@"result:%ld",result) } #pragma mark 重连 - (void)relinkWebRtcFun { [self linkWebRtcFun]; } #pragma mark 初始化其他UI - (void)initBaseUIFun { _bottomContrView = [[webRtcPlayerBottomContrView alloc] init]; [self.view addSubview:_bottomContrView]; KWeakSelf _bottomContrView.didClickButtonFun = ^(NSInteger tag) { [weakSelf didClickBottomFunBy:tag]; }; /*控制按钮*/ UIImage *driftBtnImage = [UIImage imageNamed:@"you_icon"]; controlBtn = [[UIButton alloc] init]; [controlBtn setBackgroundColor:[UIColor clearColor]]; [controlBtn setBackgroundImage:driftBtnImage forState:(UIControlStateNormal)]; [controlBtn addTarget:self action:@selector(controlBtnPressed:) forControlEvents:(UIControlEventTouchUpInside)]; [self.view addSubview:controlBtn]; //拖拽事件等 UIPanGestureRecognizer *gester = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(controlBtnPanGestureCallback:)]; [controlBtn addGestureRecognizer:gester]; //gester.delegate = self; [self initPointForControlBtnFun]; } #pragma mark 设置 controlBtn 的初始位置 - (void)initPointForControlBtnFun { CGFloat h_w_controlBtn = 60.f; /*区分横竖屏*/ if (_mediaStream.hw_w > _mediaStream.hw_h){ [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)]; }else{ //默认居右 //[mPlayerView.controlBtn setFrame:CGRectMake(mPlayerView.width - h_w_controlBtn - 20.f, (SCREEN_H - h_w_controlBtn)/2.f, h_w_controlBtn, h_w_controlBtn)]; //默认居左 [controlBtn setFrame:CGRectMake( h_w_controlBtn + 10.f, (SCREEN_H - h_w_controlBtn)/2.f, h_w_controlBtn, h_w_controlBtn)]; } } #pragma mark 定时器 - (void)setTimerCountDown { HLog(@"开启一个"); if (_playerSecondTimer) { // 取消定时器 [_playerSecondTimer invalidate]; _playerSecondTimer = nil; } // 初始化值计时数据 //self.adjustTime = 1; //self.concentTime = [iTools getNowTimeStamp]; _playerSecondTimer = [NSTimer scheduledTimerWithTimeInterval:3.0 target:self selector:@selector(timerChange) userInfo:nil repeats:YES]; [[NSRunLoop currentRunLoop] addTimer:_playerSecondTimer forMode:NSRunLoopCommonModes]; } #pragma mark 定时器响应事件 - (void)timerChange { [self extensionAdjustBtnFrameCheckAdjustTime];// 1、悬浮球3s后 自动靠边隐藏 //[self checkConcentTime];// 3、30s之后 没有收到拉流数据 自动断开链接 } #pragma mark 控制按钮点击事件 - (void)controlBtnPressed:(UIButton*)but { playerSetView *nextVC = [[playerSetView alloc] init]; [ksharedAppDelegate.window addSubview:nextVC]; [nextVC mas_makeConstraints:^(MASConstraintMaker *make) { make.left.mas_equalTo(0); make.right.mas_equalTo(0); make.top.mas_equalTo(0.f); make.bottom.mas_equalTo(0.f); }]; KWeakSelf nextVC.didClickButtonFun = ^(NSInteger tag) { switch (tag) { case 10: {//截图 //self->needScreenShotType = YES; } break; #pragma mark 重启盒子 case 11: { //[weakSelf didClickRestartFun]; } break; case 12: {//退出云机 [weakSelf exitCloudPhoneFun]; } break; case 100: { // BOOL fullscreenType = [HWDataManager getBoolWithKey:Consn_player_full_screen_show]; // if(fullscreenType){ // [weakSelf showOpenTVP2PFun]; // } // else{ // [weakSelf openTvShowFun]; // } } break; case 101: { // self->mPlayerView.controlBtn.userInteractionEnabled = NO; // dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ // self->mPlayerView.controlBtn.userInteractionEnabled = YES; // }); // [weakSelf showCloseTVP2PFun]; } break; default: break; } }; } #pragma mark 退出云机 - (void)exitCloudPhoneFun { //[self setShowImgAndVoiceTypeFun:NO]; if(_isCodeSuspendAudioType){ [[DFPlayer sharedPlayer] df_play]; } [self.navigationController popViewControllerAnimated:YES]; } #pragma mark 底部按钮事件 - (void)didClickBottomFunBy:(NSInteger)tag { int keyType = 0; if(tag == 1){//task keyType = 187; } else if(tag == 2){//home keyType = 3; } else if(tag == 3){//back keyType = 4; } if(keyType > 0){ [self didClickKeyEventFunBy:keyType]; } } #pragma mark 按键事件 // home 3 back 4 task 187 volumeUp 24 volumeDown 25 - (void)didClickKeyEventFunBy:(int)keyType { [_mediaStream sendKey:keyType]; } #pragma mark -- /*通知添加与移除*/ - (void)addKVOObserverFun { outputVolumeKVO = YES; [[AVAudioSession sharedInstance] addObserver:self forKeyPath:@"outputVolume" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld context:(void *)[AVAudioSession sharedInstance]]; } - (void)removeKVOObserverFun { if (outputVolumeKVO) { [[AVAudioSession sharedInstance] removeObserver:self forKeyPath:@"outputVolume" context:(void *)[AVAudioSession sharedInstance]]; outputVolumeKVO = NO; } } #pragma mark 系统音量键监听 - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context{ if(context == (__bridge void *)[AVAudioSession sharedInstance]) { /*音量开关打开时 允许发送指令 否则直接返回*/ float newValue = [[change objectForKey:@"new"] floatValue]; float oldValue = [[change objectForKey:@"old"] floatValue]; //HLog(@"音量 --old: %f ---new: %f",oldValue,newValue) if (newValue > oldValue) { HLog(@"\n-----音量增加"); [self didClickKeyEventFunBy:24]; } else { HLog(@"\n-----音量降低"); [self didClickKeyEventFunBy:25]; } } } #pragma mark 监听到云机的宽高以及屏幕方向 - (void)handlUIAfterGetCloudPhoneVideoWidth:(int)videoWidth videoHeight:(int)videoHeight rotation:(int)rotation { CGFloat curRate = (CGFloat)videoWidth/(CGFloat)videoHeight; if(lastVideoWHRate == curRate){ return; } didAdjusBtnType = NO; if(rotation == 0){//竖屏 //切换到竖屏 isLan = NO; [self hx_rotateToInterfaceOrientation:UIInterfaceOrientationPortrait]; [self setPoMas_makeWithImageRate:curRate]; } else if(rotation == 1){//横屏 //切换到横屏屏 isLan = YES; [self hx_rotateToInterfaceOrientation:UIInterfaceOrientationLandscapeRight]; [self setLanMas_makeWithImageRate:curRate]; } dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ [self extensionAdjustBtnFrameCheckAdjustTime]; }); } #pragma mark WebRTC 回调 MediaStreamClientEventsDelegate #pragma mark - 宽高变化 -(void)onFrameResolutionChangedFromPeerName:(NSString*)peerName videoWidth:(int)videoWidth videoHeight:(int)videoHeight rotation:(int)rotation { HLog(@"peerName:%@---%d---%d--%d",peerName,videoWidth,videoHeight,rotation) mainBlock(^{ [self handlUIAfterGetCloudPhoneVideoWidth:videoWidth videoHeight:videoHeight rotation:rotation]; }); } //code 0 成功 1失败 -(void)onAuthResultFromPeerName:(NSString*)peerName code:(int)code descriptions:(NSString*)descriptions { HLog(@"onAuthResultFromPeerName:%@---%d---%@",peerName,code,descriptions) } #pragma mark 链接发生变化 -(void)onChangeConnectionStateFromPeerName:(NSString*)peerName didChangeIceConnectionState:(RTCIceConnectionState)state { HLog(@"onChangeConnectionStateFromPeerName: state:%ld",state) switch (state) { case RTCIceConnectionStateConnected:{ //链接成功 mainBlock(^{ [self removeNewIndicator]; }); } break; case RTCIceConnectionStateCompleted: //链接完成 break; case RTCIceConnectionStateFailed: //链接失败 break; case RTCIceConnectionStateDisconnected: //链接断开 [self relinkWebRtcFun]; break; case RTCIceConnectionStateClosed: //链接关闭 break; default: break; } } - (void)dataChannelDidChangeFromPeerName:(NSString*)peerName State:(RTCDataChannelState)state{ ; } //-(void)onIceConnectedFromPeerName:(NSString*)peerName{ // HLog(@"onIceConnectedFromPeerName:%@",peerName); // mainBlock(^{ // [self removeNewIndicator]; // }); //} -(void)didGetStats:(NSString*)peerName stats:(RTC_OBJC_TYPE(RTCStatisticsReport) *)stats { HLog(@"stats:%@",stats); } @end