AudioChatTool.m 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382
  1. //
  2. // AudioChatTool.m
  3. // BuguLive
  4. //
  5. // Created by Kylin on 2024/12/2.
  6. // Copyright © 2024 xfg. All rights reserved.
  7. //
  8. #import "AudioChatTool.h"
  9. #import <UserNotifications/UserNotifications.h>
  10. @interface AudioChatTool ()
  11. @property (nonatomic,assign) BOOL limitJoinRoom;
  12. @end
  13. @implementation AudioChatTool
  14. static dispatch_once_t onceToken;
  15. static AudioChatTool *_voiceRoomVC;
  16. + (instancetype)shareInstance{
  17. dispatch_once(&onceToken, ^{
  18. _voiceRoomVC = [[AudioChatTool alloc] init];
  19. });
  20. return _voiceRoomVC;
  21. }
  22. #pragma mark 进入房间 /**回到主线程跳转*/
  23. - (void)audioGetMainPushVoiceRoomIsZhuDongCall:(BOOL)isZhuDongCall withFriendObj:(SFriendObj *)friendObj loadEndBlock:(void (^)(void))block {
  24. NSLog(@"要打开房间了。。。。。。。。。。。");
  25. if (self.limitJoinRoom) {
  26. return;
  27. }
  28. self.limitJoinRoom = YES;
  29. dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
  30. self.limitJoinRoom = NO;
  31. });
  32. dispatch_async(dispatch_get_main_queue(), ^{
  33. AudioChatViewController * voiceRoomVC = [AudioChatViewController shareVoiceRoomVC];
  34. voiceRoomVC.mChatFriend = friendObj;
  35. voiceRoomVC.isZhuDongCall = isZhuDongCall;
  36. self.recordAudioChatViewController = voiceRoomVC;
  37. voiceRoomVC.hidesBottomBarWhenPushed = YES;
  38. UIWindow *window = [UIApplication sharedApplication].keyWindow;
  39. UINavigationController * nav = [[UINavigationController alloc] initWithRootViewController:voiceRoomVC];
  40. nav.modalPresentationStyle = UIModalPresentationOverFullScreen;
  41. nav.modalTransitionStyle = UIModalTransitionStyleCoverVertical;
  42. nav.hidesBottomBarWhenPushed = YES;
  43. [window.rootViewController presentViewController:nav animated:YES completion:^{
  44. NSLog(@"打开房间了。。。。。。。。。。。");
  45. if (block) {
  46. block();
  47. }
  48. }];
  49. });
  50. }
  51. #pragma mark 进入房间 /**回到主线程跳转*/
  52. - (void)videoGetMainPushVoiceRoomIsZhuDongCall:(BOOL)isZhuDongCall withFriendObj:(SFriendObj *)friendObj loadEndBlock:(void (^)(void))block {
  53. NSLog(@"要打开房间了。。。。。。。。。。。");
  54. if (self.limitJoinRoom) {
  55. return;
  56. }
  57. self.limitJoinRoom = YES;
  58. dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
  59. self.limitJoinRoom = NO;
  60. });
  61. dispatch_async(dispatch_get_main_queue(), ^{
  62. AppDelegate *app = (AppDelegate *)[[UIApplication sharedApplication] delegate];
  63. VideoChatVC * voiceRoomVC = [VideoChatVC shareVoiceRoomVC];
  64. voiceRoomVC.mChatFriend = friendObj;
  65. voiceRoomVC.isZhuDongCall = isZhuDongCall;
  66. self.recordVideoChatVC = voiceRoomVC;
  67. voiceRoomVC.hidesBottomBarWhenPushed = YES;
  68. UIWindow *window = [UIApplication sharedApplication].keyWindow;
  69. UINavigationController * nav = [[UINavigationController alloc] initWithRootViewController:voiceRoomVC];
  70. nav.modalPresentationStyle = UIModalPresentationOverFullScreen;
  71. nav.modalTransitionStyle = UIModalTransitionStyleCoverVertical;
  72. nav.hidesBottomBarWhenPushed = YES;
  73. [window.rootViewController presentViewController:nav animated:YES completion:^{
  74. NSLog(@"打开房间了。。。。。。。。。。。");
  75. if (block) {
  76. block();
  77. }
  78. }];
  79. });
  80. }
  81. #pragma mark - 在线收到消息互动
  82. - (void)receiveCallWithNotification:(NSNotification *)notifcation {
  83. SIMMsgObj *thatmsg = (SIMMsgObj *) notifcation.object;
  84. SFriendObj* mChatFriend = [[SFriendObj alloc]initWithUserId:thatmsg.mSenderId];
  85. mChatFriend.mNick_name = thatmsg.mCoreTMsg.nickName;
  86. mChatFriend.mHead_image = thatmsg.mHeadImgUrl;
  87. // chattag.is_robot = thatmsg.is_robot;
  88. //不在通话中,忽略消息
  89. if (AppDelegate.sharedAppDelegate.isInAudioVideoChatVc == NO &&
  90. thatmsg.callAudioType > AudioChatType_call) {
  91. return;
  92. }
  93. if (thatmsg.mMsgType == MSG_PRIVATE_CallAudio) {
  94. //收到语音请求
  95. if (thatmsg.callAudioType == AudioChatType_call) {
  96. if (AppDelegate.sharedAppDelegate.isEnterLiveVC || AppDelegate.sharedAppDelegate.isInAudioVideoChatVc) {
  97. WeakSelf
  98. SIMMsgObj *obj = [mChatFriend sendCustomCallAudioTextMsg:@"接听者,忙线中" callAudioType:AudioChatType_isBusy
  99. isCall:NO
  100. block:^(SResBase *resb, SIMMsgObj *newObj) {
  101. if (!resb.msuccess)
  102. {
  103. [SVProgressHUD showErrorWithStatus:resb.mmsg];
  104. } else {
  105. }
  106. }];
  107. return;
  108. }
  109. [AudioChatTool.shareInstance audioGetMainPushVoiceRoomIsZhuDongCall:NO withFriendObj:mChatFriend loadEndBlock:^{
  110. [AudioChatTool.shareInstance.recordAudioChatViewController reloadDataWithType:thatmsg.callAudioType];
  111. }];
  112. } else if (thatmsg.callAudioType == AudioChatType_receive) {
  113. //接收者,接听语音
  114. [AudioChatTool.shareInstance.recordAudioChatViewController reloadDataWithType:thatmsg.callAudioType];
  115. } else if (thatmsg.callAudioType == AudioChatType_zhudongClose) {
  116. /** 3、挂断通话,发起者主动挂断,A给B发 */
  117. [AudioChatTool.shareInstance.recordAudioChatViewController reloadDataWithType:thatmsg.callAudioType];
  118. } else if (thatmsg.callAudioType == AudioChatType_beidongClose) {
  119. /** 4、挂断电话,接收者挂断,B给A发 */
  120. [AudioChatTool.shareInstance.recordAudioChatViewController reloadDataWithType:thatmsg.callAudioType];
  121. } else if (thatmsg.callAudioType == AudioChatType_isBusy) {
  122. /** 5、挂断电话,接收者忙线中,语音中或者在直播间中,B给A发 */
  123. [AudioChatTool.shareInstance.recordAudioChatViewController reloadDataWithType:thatmsg.callAudioType];
  124. } else if (thatmsg.callAudioType == AudioChatType_askIsNormal && thatmsg.isCall == NO) {
  125. /** 6、主动询问A是否在房间等着B通话,B给A发 */
  126. [AudioChatTool.shareInstance.recordAudioChatViewController reloadDataWithType:thatmsg.callAudioType];
  127. } else if (thatmsg.callAudioType == AudioChatType_notificationChatNormal && thatmsg.isCall) {
  128. /** 7、告诉B等着你呢,快来通话吧,A给B发 */
  129. AudioChatTool.shareInstance.recordAudioChatViewController.callIsNormal = YES;
  130. }
  131. } else if (thatmsg.mMsgType == MSG_PRIVATE_CallVideo) {
  132. //收到视频请求
  133. if (thatmsg.callAudioType == AudioChatType_call) {
  134. if (AppDelegate.sharedAppDelegate.isEnterLiveVC || AppDelegate.sharedAppDelegate.isInAudioVideoChatVc) {
  135. WeakSelf
  136. SIMMsgObj *obj = [mChatFriend sendCustomCallVideoTextMsg:@"接听者,忙线中" callAudioType:AudioChatType_isBusy
  137. isCall:NO
  138. block:^(SResBase *resb, SIMMsgObj *newObj) {
  139. if (!resb.msuccess)
  140. {
  141. [SVProgressHUD showErrorWithStatus:resb.mmsg];
  142. } else {
  143. }
  144. }];
  145. return;
  146. }
  147. WeakSelf
  148. [AudioChatTool.shareInstance videoGetMainPushVoiceRoomIsZhuDongCall:NO withFriendObj:mChatFriend loadEndBlock:^{
  149. [AudioChatTool.shareInstance.recordVideoChatVC reloadDataWithType:thatmsg.callAudioType];
  150. }];
  151. } else if (thatmsg.callAudioType == AudioChatType_receive) {
  152. //接收者,接听语音
  153. [AudioChatTool.shareInstance.recordVideoChatVC reloadDataWithType:thatmsg.callAudioType];
  154. } else if (thatmsg.callAudioType == AudioChatType_zhudongClose) {
  155. /** 3、挂断通话,发起者主动挂断,A给B发 */
  156. [AudioChatTool.shareInstance.recordVideoChatVC reloadDataWithType:thatmsg.callAudioType];
  157. } else if (thatmsg.callAudioType == AudioChatType_beidongClose) {
  158. /** 4、挂断电话,接收者挂断,B给A发 */
  159. [AudioChatTool.shareInstance.recordVideoChatVC reloadDataWithType:thatmsg.callAudioType];
  160. } else if (thatmsg.callAudioType == AudioChatType_isBusy) {
  161. /** 5、挂断电话,接收者忙线中,语音中或者在直播间中,B给A发 */
  162. [AudioChatTool.shareInstance.recordVideoChatVC reloadDataWithType:thatmsg.callAudioType];
  163. } else if (thatmsg.callAudioType == AudioChatType_askIsNormal && thatmsg.isCall == NO) {
  164. /** 6、主动询问A是否在房间等着B通话,B给A发 */
  165. [AudioChatTool.shareInstance.recordVideoChatVC reloadDataWithType:thatmsg.callAudioType];
  166. } else if (thatmsg.callAudioType == AudioChatType_notificationChatNormal && thatmsg.isCall) {
  167. /** 7、告诉B等着你呢,快来通话吧,A给B发 */
  168. AudioChatTool.shareInstance.recordVideoChatVC.callIsNormal = YES;
  169. }
  170. }
  171. }
  172. #pragma mark - VOIP推送
  173. - (void)receivePushVoipMsgWithNotification:(NSDictionary *)notification {
  174. /*
  175. "callUserID" : 167720,
  176. "callAudioType" : 1,
  177. "callNickName" : "张三",
  178. "callHeaderImg" : "",
  179. "callType" : 666
  180. */
  181. NSDictionary * dict = notification[@"aps"][@"Extras"];
  182. if (![dict isKindOfClass:NSDictionary.class] || dict == nil) {
  183. return;
  184. }
  185. BOOL isVideo = [dict[@"callType"] intValue] == MSG_PRIVATE_CallVideo ? YES : NO;
  186. if (AppDelegate.sharedAppDelegate.isEnterLiveVC || AppDelegate.sharedAppDelegate.isInAudioVideoChatVc) {
  187. SFriendObj* mChatFriend = [[SFriendObj alloc]initWithUserId:[dict[@"callUserID"] intValue]];
  188. mChatFriend.mNick_name = dict[@"callNickName"];
  189. mChatFriend.mHead_image = dict[@"callHeaderImg"];
  190. BOOL isVideo = [dict[@"callType"] intValue] == MSG_PRIVATE_CallVideo ? YES : NO;
  191. if (isVideo) {
  192. SIMMsgObj *obj = [mChatFriend sendCustomCallVideoTextMsg:@"接听者,忙线中" callAudioType:AudioChatType_isBusy
  193. isCall:NO
  194. block:^(SResBase *resb, SIMMsgObj *newObj) {
  195. if (!resb.msuccess) {
  196. [SVProgressHUD showErrorWithStatus:resb.mmsg];
  197. }
  198. }];
  199. return;
  200. }
  201. SIMMsgObj *obj = [mChatFriend sendCustomCallAudioTextMsg:@"接听者,忙线中" callAudioType:AudioChatType_isBusy
  202. isCall:NO
  203. block:^(SResBase *resb, SIMMsgObj *newObj) {
  204. if (!resb.msuccess) {
  205. [SVProgressHUD showErrorWithStatus:resb.mmsg];
  206. }
  207. }];
  208. return;
  209. }
  210. NSString * subTitle = ASLocalizedString(@"邀请你语音通话");
  211. if (isVideo) {
  212. subTitle = ASLocalizedString(@"邀请你视频通话");
  213. }
  214. UNUserNotificationCenter* center = [UNUserNotificationCenter currentNotificationCenter];
  215. UNMutableNotificationContent* content = [[UNMutableNotificationContent alloc] init];
  216. content.title = @"711 Live";
  217. content.userInfo = dict;
  218. content.body = [NSString localizedUserNotificationStringForKey:[NSString stringWithFormat:@"%@%@", dict[@"callNickName"],subTitle] arguments:nil];
  219. UNNotificationSound *customSound = [UNNotificationSound soundNamed:@"phone_ringing.mp3"];
  220. content.sound = customSound;
  221. UNTimeIntervalNotificationTrigger* trigger = [UNTimeIntervalNotificationTrigger
  222. triggerWithTimeInterval:1 repeats:NO];
  223. UNNotificationRequest * request = [UNNotificationRequest requestWithIdentifier:[NSString stringWithFormat:@"%@",dict[@"callUserID"]] content:content trigger:trigger];
  224. [center addNotificationRequest:request withCompletionHandler:^(NSError * _Nullable error) {
  225. NSLog(@"结束");
  226. }];
  227. /**
  228. 初始化计时器 每一秒振动一次
  229. @param playkSystemSound 振动方法
  230. @return
  231. */
  232. // if(_vibrationTimer){
  233. // [_vibrationTimer invalidate];
  234. // _vibrationTimer = nil;
  235. // }else{
  236. // _vibrationTimer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(playkSystemSound) userInfo:nil repeats:YES];
  237. // }
  238. }
  239. //振动
  240. //- (void)playkSystemSound{
  241. // AudioServicesPlaySystemSound(kSystemSoundID_Vibrate);
  242. //}
  243. - (void)pushAudioChatWithDict:(NSDictionary *)dict {
  244. // {
  245. // UIAlertView *alert = [UIAlertView bk_showAlertViewWithTitle:NSLocalizedString(@"TCVideoRecordView.AbandonRecord", nil) message:[NSString stringWithFormat:@"%@",dict] cancelButtonTitle:NSLocalizedString(@"Common.Cancel", nil) otherButtonTitles:@[NSLocalizedString(@"Common.OK", nil)] handler:^(UIAlertView *alertView, NSInteger buttonIndex) {
  246. //
  247. // }];
  248. // [alert show];
  249. // }
  250. //过期的推送,直接拦截,不再唤起接听页面
  251. if ([dict[@"callAudioType"] intValue] == AudioChatType_notificationChatExpired) {
  252. return;
  253. }
  254. SFriendObj * mChatFriend = [[SFriendObj alloc]initWithUserId:[dict[@"callUserID"] intValue]];
  255. mChatFriend.mNick_name = dict[@"callNickName"];
  256. mChatFriend.mHead_image = dict[@"callHeaderImg"];
  257. if ([dict[@"callType"] intValue] == MSG_PRIVATE_CallAudio) {
  258. [AudioChatTool.shareInstance audioGetMainPushVoiceRoomIsZhuDongCall:NO withFriendObj:mChatFriend loadEndBlock:^{
  259. [AudioChatTool.shareInstance.recordAudioChatViewController reloadDataWithType:AudioChatType_call];
  260. }];
  261. return;
  262. }
  263. [AudioChatTool.shareInstance videoGetMainPushVoiceRoomIsZhuDongCall:NO withFriendObj:mChatFriend loadEndBlock:^{
  264. [AudioChatTool.shareInstance.recordVideoChatVC reloadDataWithType:AudioChatType_call];
  265. }];
  266. }
  267. #pragma mark - 请求接口,推送VOIP
  268. - (void)requestCallApplyWithAudio:(BOOL)isAudio block:(void(^)(BOOL isSuccess))block {
  269. // if (block) {
  270. // block(YES);
  271. // }
  272. // return;
  273. NSMutableDictionary *parmDict = [[NSMutableDictionary alloc] init];
  274. [parmDict setObject:@"games" forKey:@"ctl"];
  275. [parmDict setObject:@"userDiamonds" forKey:@"act"];
  276. [[NetHttpsManager manager] POSTWithParameters:parmDict SuccessBlock:^(NSDictionary *responseJson) {
  277. if ([responseJson toInt:@"status"] == 1) {
  278. if (block) {
  279. block(YES);
  280. }
  281. return;
  282. }
  283. if (block) {
  284. block(NO);
  285. }
  286. } FailureBlock:^(NSError *error){
  287. if (block) {
  288. block(NO);
  289. }
  290. }];
  291. }
  292. #pragma mark - 获取其他人的在线状态
  293. - (void)getOtherIsOnlineStatusWithUserID:(NSString *)userID block:(void (^)(V2TIMUserStatusType statusType))block {
  294. if ([BGUtils isBlankString:userID]) {
  295. if (block) {
  296. block(V2TIM_USER_STATUS_UNKNOWN);
  297. }
  298. return;
  299. }
  300. [V2TIMManager.sharedInstance getUserStatus:@[userID]
  301. succ:^(NSArray<V2TIMUserStatus *> *result) {
  302. // 查询其他人的状态成功
  303. if (result.count <= 0) {
  304. //查询失败,按照离线处理
  305. if (block) {
  306. block(V2TIM_USER_STATUS_UNKNOWN);
  307. }
  308. return;
  309. }
  310. V2TIMUserStatus * obj = result.firstObject;
  311. if (block) {
  312. block(obj.statusType);
  313. }
  314. } fail:^(int code, NSString *desc) {
  315. //72001 腾讯云管理后台关闭了此功能
  316. //查询失败,按照离线处理
  317. if (block) {
  318. block(V2TIM_USER_STATUS_UNKNOWN);
  319. }
  320. }];
  321. }
  322. @end