TXRTCService.m 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414
  1. //
  2. // TXRTCService.m
  3. // TeacherDaya
  4. //
  5. // Created by 王智 on 2023/4/14.
  6. // Copyright © 2023 DayaMusic. All rights reserved.
  7. //
  8. #import "TXRTCService.h"
  9. #import "ClassroomService.h"
  10. #import "UserInfoManager.h"
  11. #import "TXIMLinsenter.h"
  12. //#import "MBProgressHUD+KSShow.h"
  13. @interface TXRTCService ()<TRTCCloudDelegate>
  14. @property (nonatomic, strong) NSString *userSig;
  15. @property (nonatomic, strong) NSString *sdkAppId;
  16. @property (nonatomic, strong) NSString *rtcAppKey;
  17. @property (nonatomic, strong) NSString *rtcUserSig;
  18. @property (nonatomic, strong) NSString *roomID;
  19. @property (nonatomic, copy) KSRTCCallback success;
  20. @property (nonatomic, copy) KSRTCCallback error;
  21. @property (nonatomic, strong) TRTCCloud *engine;
  22. @end
  23. @implementation TXRTCService
  24. + (instancetype)shareInstance {
  25. static TXRTCService *service = nil;
  26. static dispatch_once_t onceToken;
  27. dispatch_once(&onceToken, ^{
  28. service = [[self alloc] init];
  29. [service defaultAudioSetting];
  30. });
  31. return service;
  32. }
  33. - (void)defaultAudioSetting {
  34. self.ANS = 0;
  35. self.AEC = 100;
  36. self.AGC = 0;
  37. }
  38. - (void)configWithRoomConfig:(TxRTCRoomConfig *)roomConfig successCallback:(void(^)(void))callback {
  39. self.userSig = roomConfig.userSig;
  40. self.sdkAppId = roomConfig.appKey;
  41. self.rtcAppKey = roomConfig.rtcAppKey;
  42. self.rtcUserSig = roomConfig.rtcUserSig;
  43. callback();
  44. }
  45. - (void)setting3AParmWithANS:(NSInteger)ANS AEC:(NSInteger)AEC AGC:(NSInteger)AGC {
  46. self.ANS = ANS;
  47. self.AEC = AEC;
  48. self.AGC = AGC;
  49. }
  50. #pragma mark - 发布/订阅音视频流
  51. - (void)joinRTCRoom:(NSString *)roomId success:(KSRTCCallback)success failer:(KSRTCCallback)error {
  52. if (success) {
  53. self.success = success;
  54. }
  55. if (error) {
  56. self.error = error;
  57. }
  58. [self.engine enterRoom:[self getTRTCRoomConfig:roomId] appScene:TRTCAppSceneVideoCall];
  59. self.engine.delegate = self;
  60. [self configDefaultHardwareStatus];
  61. }
  62. - (void)configDefaultHardwareStatus {
  63. [self configVideoAndAudioSetting];
  64. BOOL micOn = [ClassroomService sharedService].currentRoom.currentMember.microphoneEnable;
  65. [self setMicrophoneDisable:!micOn];
  66. BOOL cameraOn = [ClassroomService sharedService].currentRoom.currentMember.cameraEnable;
  67. [self setCameraDisable:!cameraOn];
  68. // 开启音量检测
  69. TRTCAudioVolumeEvaluateParams *parms = [[TRTCAudioVolumeEvaluateParams alloc] init];
  70. parms.interval = 300;
  71. [[TRTCCloud sharedInstance] enableAudioVolumeEvaluation:YES withParams:parms];
  72. }
  73. - (void)leaveRoom:(KSRTCCallback)callback {
  74. if (callback) {
  75. self.success = callback;
  76. }
  77. [self.engine exitRoom];
  78. _engine = nil;
  79. [TRTCCloud destroySharedIntance];
  80. if (callback) {
  81. callback(1);
  82. }
  83. }
  84. - (void)publishStream {
  85. NSString *currentUserID = [ClassroomService sharedService].currentRoom.currentMemberId;
  86. NSString *streamId = [NSString stringWithFormat:@"%@_%@", self.roomID, currentUserID];
  87. [self.engine startPublishing:streamId type:TRTCVideoStreamTypeBig];
  88. }
  89. - (void)configVideoAndAudioSetting {
  90. [self.engine startLocalAudio:TRTCAudioQualityMusic];
  91. TRTCVideoEncParam *videoEncParams = [[TRTCVideoEncParam alloc] init];
  92. videoEncParams.videoFps = 15.0f;
  93. videoEncParams.resMode = TRTCVideoResolutionModeLandscape;
  94. videoEncParams.videoResolution = TRTCVideoResolution_640_480;
  95. [self.engine setVideoEncoderParam:videoEncParams];
  96. [self.engine setGSensorMode:TRTCGSensorMode_UIFixLayout];
  97. // [self.engine setVideoMuteImage:[self generalCloseImage] fps:5];
  98. [self config3AWithANS:self.ANS AEC:self.AEC AGC:self.AGC];
  99. }
  100. - (UIImage *)generalCloseImage {
  101. UIView *backView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 300, 300)];
  102. backView.backgroundColor = HexRGB(0xE9EDF3);
  103. UIView *layerView = [[UIView alloc] initWithFrame:CGRectMake((300 - 84)/2.0f, (300 - 84)/2.0f, 84, 84)];
  104. layerView.backgroundColor = HexRGB(0xffffff);
  105. layerView.layer.cornerRadius = 42;
  106. [backView addSubview:layerView];
  107. NSString *imageName = UserDefaultObjectForKey(AvatarUrlKey);
  108. UIImageView *avatar = [[UIImageView alloc] initWithFrame:CGRectMake(2, 2, 80, 80)];
  109. if ([NSString isEmptyString:imageName]) {
  110. imageName = USERDEFAULT_LOGO;
  111. [avatar setImage:[UIImage imageNamed:imageName]];
  112. }
  113. else {
  114. [avatar sd_setImageWithURL:[NSURL URLWithString:[imageName getUrlEndcodeString]] placeholderImage:[UIImage imageNamed:USERDEFAULT_LOGO]];
  115. }
  116. [layerView addSubview:avatar];
  117. avatar.layer.cornerRadius = 40;
  118. avatar.clipsToBounds = YES;
  119. avatar.contentMode = UIViewContentModeScaleAspectFill;
  120. //高清方法
  121. //第一个参数表示区域大小 第二个参数表示是否是非透明的。如果需要显示半透明效果,需要传NO,否则传YES。第三个参数就是屏幕密度了
  122. CGSize size = CGSizeMake(backView.layer.bounds.size.width, backView.layer.bounds.size.height);
  123. UIGraphicsBeginImageContextWithOptions(size, NO, [UIScreen mainScreen].scale);
  124. [backView.layer renderInContext:UIGraphicsGetCurrentContext()];
  125. UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
  126. UIGraphicsEndImageContext();
  127. return image;
  128. }
  129. - (void)renderLocalUserInView:(UIView *)displayView isCameraEnable:(BOOL)cameraEnable {
  130. if (cameraEnable) {
  131. [self.engine setLocalRenderParams:[self getRenderParms:YES]];
  132. [self.engine startLocalPreview:[self isFrontCamera] view:displayView];
  133. }
  134. else {
  135. [self stopLocalPreview];
  136. }
  137. }
  138. - (void)stopLocalPreview {
  139. [self.engine stopLocalPreview];
  140. }
  141. - (void)renderRemoteUser:(NSString *)userId inView:(UIView *)displayView {
  142. [self cancleRenderUserVideo:userId];
  143. [self.engine setRemoteRenderParams:userId streamType:TRTCVideoStreamTypeBig params:[self getRenderParms:NO]];
  144. [self.engine startRemoteView:userId streamType:TRTCVideoStreamTypeBig view:displayView];
  145. }
  146. - (void)cancleRenderUserVideo:(NSString *)userId {
  147. NSString *currentUserID = [ClassroomService sharedService].currentRoom.currentMemberId;
  148. if (![userId isEqualToString:currentUserID]) {
  149. [self.engine stopRemoteView:userId streamType:TRTCVideoStreamTypeBig];
  150. }
  151. else {
  152. }
  153. }
  154. - (TRTCParams *)getTRTCRoomConfig:(NSString *)roomId {
  155. TRTCParams *params = [[TRTCParams alloc] init];
  156. params.sdkAppId = [self.sdkAppId intValue];
  157. params.userSig = self.rtcUserSig;
  158. params.strRoomId = roomId;
  159. params.userId = UserDefault(IM_USERID);
  160. return params;
  161. }
  162. // 配置3A参数
  163. - (void)config3AWithANS:(NSInteger)ANS AEC:(NSInteger)AEC AGC:(NSInteger)AGC {
  164. // [MBProgressHUD ksShowMessage:[NSString stringWithFormat:@"ANS : %zd, AEC: %zd, AGC:%zd", ANS, AEC, AGC]];
  165. [self configANSParm:ANS];
  166. [self configAECParm:AEC];
  167. [self configAGCParm:AGC];
  168. }
  169. // 背景音抑制
  170. - (void)configANSParm:(NSInteger)number {
  171. NSMutableDictionary *dic = [NSMutableDictionary dictionary];
  172. [dic setValue:@"enableAudioANS" forKey:@"api"];
  173. NSMutableDictionary *subDic = [NSMutableDictionary dictionary];
  174. if (number > 0) {
  175. [subDic setValue:@(1) forKey:@"enable"];
  176. [subDic setValue:@(number) forKey:@"level"];
  177. }
  178. else {
  179. [subDic setValue:@(0) forKey:@"enable"];
  180. [subDic setValue:@(0) forKey:@"level"];
  181. }
  182. [dic setValue:subDic forKey:@"params"];
  183. NSData *data = [NSJSONSerialization dataWithJSONObject:dic options:kNilOptions error:nil];
  184. NSString *jsonString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
  185. [self.engine callExperimentalAPI:jsonString];
  186. }
  187. // 回声消除
  188. - (void)configAECParm:(NSInteger)number {
  189. NSMutableDictionary *dic = [NSMutableDictionary dictionary];
  190. [dic setValue:@"enableAudioAEC" forKey:@"api"];
  191. NSMutableDictionary *subDic = [NSMutableDictionary dictionary];
  192. if (number > 0) {
  193. [subDic setValue:@(1) forKey:@"enable"];
  194. [subDic setValue:@(number) forKey:@"level"];
  195. }
  196. else {
  197. [subDic setValue:@(0) forKey:@"enable"];
  198. [subDic setValue:@(0) forKey:@"level"];
  199. }
  200. [dic setValue:subDic forKey:@"params"];
  201. NSData *data = [NSJSONSerialization dataWithJSONObject:dic options:kNilOptions error:nil];
  202. NSString *jsonString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
  203. [self.engine callExperimentalAPI:jsonString];
  204. }
  205. // 自动增益
  206. - (void)configAGCParm:(NSInteger)number {
  207. NSMutableDictionary *dic = [NSMutableDictionary dictionary];
  208. [dic setValue:@"enableAudioAGC" forKey:@"api"];
  209. NSMutableDictionary *subDic = [NSMutableDictionary dictionary];
  210. if (number > 0) {
  211. [subDic setValue:@(1) forKey:@"enable"];
  212. [subDic setValue:@(number) forKey:@"level"];
  213. }
  214. else {
  215. [subDic setValue:@(0) forKey:@"enable"];
  216. [subDic setValue:@(0) forKey:@"level"];
  217. }
  218. [dic setValue:subDic forKey:@"params"];
  219. NSData *data = [NSJSONSerialization dataWithJSONObject:dic options:kNilOptions error:nil];
  220. NSString *jsonString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
  221. [self.engine callExperimentalAPI:jsonString];
  222. }
  223. #pragma mark --- TRTCCloudDelegate
  224. - (void)onEnterRoom:(NSInteger)result {
  225. if (result > 0) {
  226. if (self.success) {
  227. self.success(result);
  228. }
  229. }
  230. else {
  231. if (self.error) {
  232. [self.engine exitRoom];
  233. _engine = nil;
  234. [TRTCCloud destroySharedIntance];
  235. self.error(result);
  236. }
  237. }
  238. }
  239. - (void)onExitRoom:(NSInteger)reason {
  240. if (self.success) {
  241. self.success(reason);
  242. }
  243. }
  244. - (void)onError:(TXLiteAVError)errCode errMsg:(NSString *)errMsg extInfo:(NSDictionary *)extInfo {
  245. NSLog(@"tx rtc error --- code %d message : %@", errCode, errMsg);
  246. if (self.error) {
  247. self.error(errCode);
  248. }
  249. }
  250. #pragma mark ---- 用户进出房间
  251. - (void)onRemoteUserEnterRoom:(NSString *)userId {
  252. }
  253. - (void)onRemoteUserLeaveRoom:(NSString *)userId reason:(NSInteger)reason {
  254. }
  255. - (void)onUserVideoAvailable:(NSString *)userId available:(BOOL)available {
  256. }
  257. - (void)onUserAudioAvailable:(NSString *)userId available:(BOOL)available {
  258. }
  259. // 网络质量
  260. - (void)onNetworkQuality:(TRTCQualityInfo *)localQuality remoteQuality:(NSArray<TRTCQualityInfo *> *)remoteQuality {
  261. if (self.delegate && [self.delegate respondsToSelector:@selector(didReportNetworkQuality:remoteQuality:)]) {
  262. [self.delegate didReportNetworkQuality:localQuality.quality remoteQuality:remoteQuality];
  263. }
  264. }
  265. // 音量
  266. - (void)onUserVoiceVolume:(NSArray<TRTCVolumeInfo *> *)userVolumes totalVolume:(NSInteger)totalVolume {
  267. if (self.delegate && [self.delegate respondsToSelector:@selector(didReportUserVolume:)]) {
  268. [self.delegate didReportUserVolume:userVolumes];
  269. }
  270. }
  271. #pragma mark ---- 不播放音频流
  272. - (void)unPlayRemoteStudentAudioStreamExcept:(NSString *)studentId {
  273. NSMutableArray *memberList = [[ClassroomService sharedService].currentRoom.memberList mutableCopy];
  274. for (RoomMember *member in memberList) {
  275. if (member.role == RoleStudent) {
  276. if ([member.userId isEqualToString:studentId]) {
  277. [self.engine setRemoteAudioVolume:member.userId volume:100];
  278. }
  279. else {
  280. [self.engine setRemoteAudioVolume:member.userId volume:0];
  281. }
  282. }
  283. }
  284. }
  285. - (void)playAllRemoteStudentAudioStream {
  286. NSMutableArray *memberList = [[ClassroomService sharedService].currentRoom.memberList mutableCopy];
  287. for (RoomMember *member in memberList) {
  288. if (member.role == RoleStudent) {
  289. [self.engine setRemoteAudioVolume:member.userId volume:100];
  290. }
  291. }
  292. }
  293. - (void)unPlayRemoteStudentWithId:(NSString *)studentId {
  294. if (![NSString isEmptyString:studentId]) {
  295. [[TRTCCloud sharedInstance] setRemoteAudioVolume:studentId volume:0];
  296. }
  297. }
  298. #pragma mark - 顶部工具栏接口
  299. /**
  300. 关闭/打开麦克风
  301. @param disable YES 关闭,NO 打开
  302. */
  303. - (void)setMicrophoneDisable:(BOOL)disable {
  304. if (disable) {
  305. [self.engine setAudioCaptureVolume:0];
  306. }
  307. else {
  308. [self.engine setAudioCaptureVolume:100];
  309. }
  310. }
  311. /**
  312. 采集运行中关闭或打开摄像头
  313. @param disable YES 关闭,否则打开
  314. */
  315. - (void)setCameraDisable:(BOOL)disable {
  316. [self.engine muteLocalVideo:TRTCVideoStreamTypeBig mute:disable];
  317. }
  318. /**
  319. 切换前后摄像头
  320. */
  321. - (void)switchCamera {
  322. TXDeviceManager *deviceManager = [self.engine getDeviceManager];
  323. BOOL isFrontCamera = [deviceManager isFrontCamera];
  324. [deviceManager switchCamera:!isFrontCamera];
  325. }
  326. - (BOOL)isFrontCamera {
  327. TXDeviceManager *deviceManager = [self.engine getDeviceManager];
  328. BOOL isFrontCamera = [deviceManager isFrontCamera];
  329. return isFrontCamera;
  330. }
  331. /**
  332. 切换使用外放/听筒
  333. */
  334. - (void)useSpeaker:(BOOL)useSpeaker {
  335. TXDeviceManager *deviceManager = [self.engine getDeviceManager];
  336. TXAudioRoute route = useSpeaker ? TXAudioRouteSpeakerphone :TXAudioRouteEarpiece;
  337. [deviceManager setAudioRoute:route];
  338. }
  339. - (TRTCRenderParams *)getRenderParms:(BOOL)isLocal {
  340. TRTCRenderParams *parms = [[TRTCRenderParams alloc] init];
  341. parms.fillMode = TRTCVideoFillMode_Fill;
  342. parms.mirrorType = TRTCVideoMirrorTypeAuto;
  343. return parms;
  344. }
  345. - (TRTCCloud *)engine {
  346. if (!_engine) {
  347. _engine = [TRTCCloud sharedInstance];
  348. }
  349. return _engine;
  350. }
  351. @end