TXRTCService.m 14 KB

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