注:由于个人版本构建不同,所以备注代码和方案不同!
第一.多方视频(自己集成NIMSDK和注册网易云信账号)
0.导入头文件 //多人视频
#import
#import
#import "UnityFunction.h"
1.注册SDK(appKey 和 cerName根据自己账号填写,自己导入头文件)
NSString *appKey = @"a543326452XXX285fd196b19524e0c55";
NSString *cerName = @"https://app.nXXXase.im/api";
[[NIMSDK sharedSDK] registerWithAppID:appKey cerName:cerName];
2.注册网易云信服务器(token自己定义 和安卓统一,否则无法互通音视频)(注册和登录方法是另行封装的)
注: #define Password @"NIMSDK/NIMSDK_User_PassWord"
- (void)regist:(NSString*)account result:(LoginRegist)result {
NSDictionary *params =@{@"accid":account,
@"props":@"",
@"token":Password,
@"icon":@""};
[[NIMServerAPI sharedAPI] request:@"https://api.netease.im/nimserver/user/create.action" params:params completion:^(NSError *error, NSDictionary *resultDict) {
self.result = result;
if (error) {
_result(@"注册失败", error.code);
} else {
_result(@"注册成功", 200);
}
}];
}
3.登录(token自己定义 和安卓统一,否则无法互通音视频)
- (void)login:(NSString*)account result:(LoginRegist)result {
[[[NIMSDK sharedSDK] loginManager] login:account token:Password completion:^(NSError *error) {
self.result = result;
if (error) {
_result(@"登录失败", error.code);
} else {
_result(@"登录成功", 200);
// if (_userInfo) {
// _userInfo.userID =account;
// _userInfo->userPswd =Password;
}
// [_userInfo saveCurrentAccount];
}
}];
}
4.创建音视频和代理,创建meeting
//音视频相关
- (void)createVideoAndAudio {
NIMNetCallMeeting *meeting = [[NIMNetCallMeeting alloc] init];
meeting.name = _roomModel.number;
if (![[NIMSDK sharedSDK].loginManager isLogined]) {
NSLog(@"当前登录用户ID:%@",_currentUserID);
[[LoginOrRegist shareUserInfo]regist:_currentUserID result:^(NSString *message, NSInteger code) {
[[LoginOrRegist shareUserInfo] login:_currentUserID result:^(NSString *message, NSInteger code) {
if (code == 200) {
NSLog(@"登录成功,进入房间");
[self joinNetCallWithRMeeting:meeting];
} else {
NSLog(@"登录失败原因%ld",(long)code);
}
}];
}];
} else {
NSLog(@"用户已经登录, 无需再登录, 正加入房间");
[self joinNetCallWithRMeeting:meeting];
}
}
5.预约会议相关方法(注:UnityFunction方法是封装的是传给U3D的消息,可忽视)
- (void)reserveMeetingWithRoomId:(NSString *)roomId{
NIMNetCallMeeting *meeting = [[NIMNetCallMeeting alloc] init];
meeting.name = roomId;
meeting.type = NIMNetCallMediaTypeVideo;
meeting.ext = @"哈哈哈哈";
meeting.actor = NO;
[[NIMAVChatSDK sharedSDK].netCallManager reserveMeeting:meeting completion:^(NIMNetCallMeeting * _Nonnull meeting, NSError * _Nonnull error) {
if (!error) {
// [UnityFunction sendUnityMessage:0 function:UnityMessageCreateRoomResult error:meeting.name];
NSLog(@"预定成功 ,进入房间");
[self joinNetCallWithRMeeting:meeting];
} else {
if (error.code == 417) {
// [UnityFunction sendUnityMessage:417 function:UnityMessageCreateRoomResult error:@"该房间已存在"];
[self joinNetCallWithRMeeting:meeting];
} else {
// [UnityFunction sendUnityMessage:(int)error.code function:UnityMessageCreateRoomResult error:error.domain];
NSLog(@"预定房间失败");
}
}
}];
}
6.加入会议相关方法(PermissionTool方法是独自封装的相机权限、麦克风权限等手动方法,可删除不管)
- (void)joinNetCallWithRMeeting:(NIMNetCallMeeting *)rMeeting {
[PermissionTool getCamerasPermission:^(NSInteger authStatus) {
if (authStatus ==1) {
[PermissionTool getMicrophonePermission:^(NSInteger authStatus) {
if (authStatus == 1) {
NIMNetCallOption *callOption =[[NIMNetCallOption alloc]init];
// 发送视频质量(SDK会处理 有可能无效)
callOption.preferredVideoQuality =NIMNetCallVideoQualityDefault;
// 禁止剪裁
callOption.disableVideoCropping =NO;
// 自动旋转远端画面
callOption.autoRotateRemoteVideo =YES;
// 期望的视频编码器
callOption.preferredVideoEncoder =NIMNetCallVideoCodecDefault;
// 期望的视频解码器
callOption.preferredVideoDecoder =NIMNetCallVideoCodecDefault;
// 是否使用后置摄像头
callOption.startWithBackCamera =NO;
// 启用互动直播
callOption.enableBypassStreaming =YES;
// 互动直播推流地址
callOption.bypassStreamingUrl =nil;
// 是否在服务器录制音频
callOption.serverRecordAudio =YES;
callOption.autoDeactivateAudioSession = NO;
// 是否在服务器录制视频
callOption.serverRecordVideo =YES;
// 加入会议的类型->音频/视频
rMeeting.type =NIMNetCallMediaTypeVideo;
// 是否发送音视频数据
rMeeting.actor = YES;
// 网路电话配置
rMeeting.option = callOption;
//进入房间聊天
[[NIMAVChatSDK sharedSDK].netCallManager joinMeeting:rMeeting completion:^(NIMNetCallMeeting * _Nonnull meeting, NSError * _Nonnull error) {
if (!error) {
NSLog(@"进入成功");
//默认关闭所有人视频
[[NIMAVChatSDK sharedSDK].netCallManager setCameraDisable:YES];
[[NIMAVChatSDK sharedSDK].netCallManager setMute:YES];
} else {
NSLog(@"进入失败");
[self reserveMeetingWithRoomId:_roomModel.number];
}
}];
} else {
NSLog(@"用户拒绝访问麦克风");
}
}];
} else {
NSLog(@"用户拒绝访问摄像头");
}
}];
}
**注:终点标注两个属性 **
第一:callOption.autoDeactivateAudioSession = NO; 这个属性是控制 “结束网络通话时自动停止AudioSession” 用的;做游戏界面,由于需要进入主页面有背景音乐,然后进入到游戏房间需要停止背景音乐,并在中途插入类似狼人杀的法官语音,退出后由于退出meeting会议,背景音乐消失,这个时候想让主页的背景音乐响起来就需要设置这个属性为NO!(我的理解是这个属性控制了音频相关控制设备,默认为占用状态)
第二:rMeeting.actor = YES; meeting的这个actor属性是设置旁观者模式或者说是音视频显示主角;actor设置成YES的话,默认进入meeting后会自动对进入房间所有人进行拉流和推流,产生流量使用,并且打开所有人的摄像头和麦克风,适用于双人视频;如果想做类似于轮到谁谁音视频打开这种,需要默认设置actor为YES,并关闭摄像头和麦克风
[[NIMAVChatSDK sharedSDK].netCallManager setCameraDisable:YES];
[[NIMAVChatSDK sharedSDK].netCallManager setMute:YES];
7.离开会议
- (void)MSUNetCallManagerLeaveMeeting {
NIMNetCallMeeting *meeting = [[NIMNetCallMeeting alloc] init];
meeting.name = _roomModel.number;
[[NIMAVChatSDK sharedSDK].netCallManager leaveMeeting:meeting];
}
8.代理方法(NIMNetCallManagerDelegate代理遵循)
// 远程视频图层(属性相关)
@property (nonatomic, strong) NTESGLView *videoView;
// 远本地视频View;
@property (nonatomic, weak) CALayer *localLayer;
/// 远程视频 (是控制远程视频流)
- (void)onRemoteYUVReady:(NSData *)yuvData width:(NSUInteger)width height:(NSUInteger)height from:(NSString *)user {
if (yuvData) {
_videoView.hidden = NO;
[_videoView render:yuvData width:width height:height];
} else {
_videoView.hidden =YES;
}
}
/// 本地视频 (此处是控制本地视频流)
- (void)onLocalPreviewReady:(CALayer *)layer {
[self isShowLocalPreviewPeady:NO aLayer:layer];
}
- (void)isShowLocalPreviewPeady:(BOOL)isShow aLayer:(CALayer*)layer {
if (!layer) {
layer =_localLayer;
}
layer.frame =CGRectMake(0, 0, WIDTH, HEIGHT);
_localLayer =layer;
_localLayer.hidden =!isShow;
[_videoView.layer addSublayer:_localLayer];
}
9.ijksdl (平心而论,此处这个是最坑爹的一个,无法言喻表达:呵呵哒!)
ijksdl属于IJKPlayer的不常用SDK的一部分,(对于这个,呵呵哒);IJKPlayer功能不叙述了,直播必须!集成这个ijksdl是云信中必有得,其中 NTESGLView 就是对 NTESIJKSDLGLView 的拉流封装;
集成:1)导入 ijksdl文件夹(此处切记,必须将此文件夹放置工程下的第一个位置,不然会出现莫名其妙的错误,相对和绝对路径混乱等错误);
2)拖入文件路径进入 TARGETS - Build Setting - Header Seacher Paths (此处一定要注意,思密达)
3)集成 NIMSDK时候,会出现 $(inherited) 相关信息警告,找到三个属性分别将$(inherited)添加进去并放置到第一个位置;
10.更改 .m文件类型,使之可以正常使用ijksdl相关文件和代码