AudioChatViewController.m 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799
  1. //
  2. // AudioChatViewController.m
  3. // BuguLive
  4. //
  5. // Created by Kylin on 2024/12/2.
  6. // Copyright © 2024 xfg. All rights reserved.
  7. //
  8. #import "AudioChatViewController.h"
  9. #import "TMSmallRoomView.h"
  10. #import "AudioChatTool.h"
  11. typedef void(^IsNormalChatBlock)(BOOL isNormal);
  12. @interface AudioChatViewController ()<TRTCCloudDelegate,AVAudioPlayerDelegate>
  13. @property (nonatomic,strong) UILabel * timesLabel;
  14. @property (nonatomic,strong) TRTCCloud * trtcCloud;
  15. @property (nonatomic,strong) UILabel * tipLabel;
  16. //通话中View
  17. @property (nonatomic,strong) UIView * chatBotoomView;
  18. @property (nonatomic,strong) UIButton * receiveButton;
  19. @property (nonatomic,strong) UIButton * receiveCloseButton;
  20. @property (nonatomic,assign) int timesCount;
  21. //接听中View
  22. @property (nonatomic,strong) UIView * receiveBottomView;
  23. @property (nonatomic,strong) UIButton * maikefengButton;
  24. @property (nonatomic,strong) UILabel * maikefengLabel;
  25. @property (nonatomic,strong) UIButton * closeButton;
  26. @property (nonatomic,strong) UILabel * closeLabel;
  27. @property (nonatomic,strong) UIButton * yangshengqiButton;
  28. @property (nonatomic,strong) UILabel * yangshengqiLabel;
  29. @property(nonatomic,strong)AVAudioPlayer *player;//播放
  30. //用户记录分钟数,用户扣费判断
  31. @property (nonatomic,assign) int lastMin;
  32. @property (nonatomic,copy) IsNormalChatBlock isNormalChatBlock;
  33. @end
  34. @implementation AudioChatViewController
  35. static dispatch_once_t onceToken;
  36. static AudioChatViewController *_voiceRoomVC;
  37. + (instancetype)shareVoiceRoomVC{
  38. dispatch_once(&onceToken, ^{
  39. _voiceRoomVC = [[AudioChatViewController alloc] init];
  40. });
  41. return _voiceRoomVC;
  42. }
  43. /**销毁房间*/
  44. + (void)destoryShareRootVC {
  45. /**更新打开房间的状态*/
  46. AppDelegate.sharedAppDelegate.isInAudioVideoChatVc = NO;
  47. // app.showRoomVc = NO;
  48. // app.IsInVoiceRoom = NO;
  49. NSLog(@"房间销毁了。。。。。。。。。。。1");
  50. /**离开房间*/
  51. [AudioChatViewController.shareVoiceRoomVC.navigationController dismissViewControllerAnimated:YES completion:^{}];
  52. [AudioChatViewController.shareVoiceRoomVC.trtcCloud exitRoom];
  53. [TRTCCloud destroySharedInstance];
  54. onceToken = 0;
  55. _voiceRoomVC = nil;
  56. //小屏的时候,也要直接销毁掉
  57. if (AppDelegate.sharedAppDelegate.hasSmallAudioVideoView) {
  58. [[TMSmallRoomView sharedInstance] dismiss];
  59. }
  60. NSLog(@"房间销毁了。。。。。。。。。。。2");
  61. }
  62. - (void)viewWillAppear:(BOOL)animated {
  63. [super viewWillAppear:animated];
  64. self.navigationController.navigationBar.hidden = YES;
  65. }
  66. - (void)viewWillDisappear:(BOOL)animated {
  67. [super viewWillDisappear:animated];
  68. self.navigationController.navigationBar.hidden = NO;
  69. }
  70. - (void)viewDidLoad {
  71. [super viewDidLoad];
  72. AppDelegate.sharedAppDelegate.isInAudioVideoChatVc = YES;
  73. self.lastMin = -1;
  74. //基础UI
  75. [self initChatBaseUI];
  76. // 音量监听
  77. [[UIApplication sharedApplication] beginReceivingRemoteControlEvents];
  78. [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(volumeChanged:) name:@"AVSystemController_SystemVolumeDidChangeNotification" object:nil];
  79. [[NSNotificationCenter defaultCenter] postNotificationName:@"MSG_VIDEO_LINE_CALL" object:nil];
  80. }
  81. - (void)initChatBaseUI {
  82. UIImageView * bgImgV = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT)];
  83. bgImgV.image = [UIImage imageNamed:@"audioChatbgicon"];
  84. [self.view addSubview:bgImgV];
  85. UIButton * backVerticalBtn = [[UIButton alloc]initWithFrame:CGRectMake(15,StatusBarHeight, 44, 44)];
  86. [backVerticalBtn setImage:[UIImage imageNamed:@"audioChatSmallIcon"] forState:UIControlStateNormal];
  87. [backVerticalBtn addTarget:self action:@selector(backBtnClick) forControlEvents:UIControlEventTouchUpInside];
  88. [self.view addSubview:backVerticalBtn];
  89. _timesLabel = [[UILabel alloc] initWithFrame:CGRectMake(60, 0, SCREEN_WIDTH - 120, 30)];
  90. self.timesLabel.centerY = backVerticalBtn.centerY;
  91. self.timesLabel.textAlignment = NSTextAlignmentCenter;
  92. self.timesLabel.textColor = UIColor.whiteColor;
  93. self.timesLabel.font = [UIFont boldSystemFontOfSize:16];
  94. self.timesLabel.text = @"00:00";
  95. self.timesLabel.hidden = YES;
  96. [self.view addSubview:self.timesLabel];
  97. UIImageView * headerImgV = [[UIImageView alloc] initWithFrame:CGRectMake((SCREEN_WIDTH - 90)/2, NavigationHeight + 133, 90, 90)];
  98. headerImgV.layer.cornerRadius = 10;
  99. headerImgV.layer.masksToBounds = YES;
  100. [headerImgV sd_setImageWithURL:[NSURL URLWithString:self.mChatFriend.mHead_image] placeholderImage:kDefaultPreloadHeadImg];
  101. [self.view addSubview:headerImgV];
  102. UILabel * nicknameLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, headerImgV.bottom + 10, SCREEN_WIDTH, 30)];
  103. nicknameLabel.textAlignment = NSTextAlignmentCenter;
  104. nicknameLabel.textColor = UIColor.whiteColor;
  105. nicknameLabel.font = [UIFont boldSystemFontOfSize:21];
  106. nicknameLabel.text = self.mChatFriend.mNick_name;
  107. [self.view addSubview:nicknameLabel];
  108. #pragma mark - 接听中UI
  109. _receiveBottomView = [[UIView alloc] initWithFrame:CGRectMake(0, SCREEN_HEIGHT - SafeAreaBottomHeight - 20 - 70, SCREEN_WIDTH, 70)];
  110. // self.receiveBottomView.layer.borderColor = UIColor.redColor.CGColor;
  111. // self.receiveBottomView.layer.borderWidth = 1;
  112. self.receiveBottomView.hidden = YES;
  113. [self.view addSubview:self.receiveBottomView];
  114. _receiveCloseButton = [UIButton buttonWithType:UIButtonTypeCustom];
  115. self.receiveCloseButton.frame = CGRectMake(25, 0, 70, 70);
  116. [self.receiveCloseButton setBackgroundImage:[UIImage imageNamed:@"audioclosebtnbg"] forState:UIControlStateNormal];
  117. [self.receiveCloseButton setBackgroundImage:[UIImage imageNamed:@"audioclosebtnbg"] forState:UIControlStateSelected];
  118. [self.receiveBottomView addSubview:self.receiveCloseButton];
  119. [self.receiveCloseButton addTarget:self action:@selector(receiveCloseButtonClick) forControlEvents:UIControlEventTouchUpInside];
  120. _receiveButton = [UIButton buttonWithType:UIButtonTypeCustom];
  121. self.receiveButton.frame = CGRectMake(SCREEN_WIDTH - 25 - 70, 0, 70, 70);
  122. [self.receiveButton setBackgroundImage:[UIImage imageNamed:@"audioreceivebtnbg"] forState:UIControlStateNormal];
  123. [self.receiveButton setBackgroundImage:[UIImage imageNamed:@"audioreceivebtnbg"] forState:UIControlStateSelected];
  124. [self.receiveBottomView addSubview:self.receiveButton];
  125. [self.receiveButton addTarget:self action:@selector(receiveButtonClick) forControlEvents:UIControlEventTouchUpInside];
  126. #pragma mark - 通话中UI
  127. _chatBotoomView = [[UIView alloc] initWithFrame:CGRectMake(0, SCREEN_HEIGHT - SafeAreaBottomHeight - 40 - 70 - 20, SCREEN_WIDTH, 70+40)];
  128. // self.chatBotoomView.layer.borderColor = UIColor.redColor.CGColor;
  129. // self.chatBotoomView.layer.borderWidth = 1;
  130. self.chatBotoomView.hidden = YES;
  131. [self.view addSubview:self.chatBotoomView];
  132. _tipLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, self.chatBotoomView.top - 60, SCREEN_WIDTH, 30)];
  133. self.tipLabel.textAlignment = NSTextAlignmentCenter;
  134. self.tipLabel.textColor = UIColor.whiteColor;
  135. self.tipLabel.font = [UIFont systemFontOfSize:16];
  136. self.tipLabel.text = ASLocalizedString(@"邀请你语音通话");
  137. self.tipLabel.textColor = [UIColor colorWithHex:0x999999];
  138. self.tipLabel.hidden = YES;
  139. [self.view addSubview:self.tipLabel];
  140. _maikefengButton = [UIButton buttonWithType:UIButtonTypeCustom];
  141. self.maikefengButton.frame = CGRectMake((SCREEN_WIDTH - 70*3)/4, 0, 70, 70);
  142. [self.maikefengButton setBackgroundImage:[UIImage imageNamed:@"maikefengopen"] forState:UIControlStateNormal];
  143. [self.maikefengButton setBackgroundImage:[UIImage imageNamed:@"maikefengclose"] forState:UIControlStateSelected];
  144. [self.chatBotoomView addSubview:self.maikefengButton];
  145. [self.maikefengButton addTarget:self action:@selector(maikeFengButtonClick) forControlEvents:UIControlEventTouchUpInside];
  146. _maikefengLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, self.maikefengButton.bottom + 10, SCREEN_WIDTH/3, 20)];
  147. self.maikefengLabel.centerX = self.maikefengButton.centerX;
  148. self.maikefengLabel.textAlignment = NSTextAlignmentCenter;
  149. self.maikefengLabel.font = [UIFont systemFontOfSize:16];
  150. self.maikefengLabel.textColor = [UIColor colorWithHex:0x999999];
  151. self.maikefengLabel.text = ASLocalizedString(@"麦克风已开启");
  152. [self.chatBotoomView addSubview:self.maikefengLabel];
  153. _closeButton = [UIButton buttonWithType:UIButtonTypeCustom];
  154. self.closeButton.frame = CGRectMake((SCREEN_WIDTH - 70*3)/4*2+70, self.maikefengButton.top, 70, 70);
  155. [self.closeButton setBackgroundImage:[UIImage imageNamed:@"audioclosebtnbg"] forState:UIControlStateNormal];
  156. [self.closeButton setBackgroundImage:[UIImage imageNamed:@"audioclosebtnbg"] forState:UIControlStateSelected];
  157. [self.chatBotoomView addSubview:self.closeButton];
  158. [self.closeButton addTarget:self action:@selector(closeButtonClick) forControlEvents:UIControlEventTouchUpInside];
  159. _closeLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, self.maikefengButton.bottom + 10, SCREEN_WIDTH/3, 20)];
  160. self.closeLabel.centerX = self.closeButton.centerX;
  161. self.closeLabel.textAlignment = NSTextAlignmentCenter;
  162. self.closeLabel.font = [UIFont systemFontOfSize:16];
  163. self.closeLabel.textColor = [UIColor colorWithHex:0x999999];
  164. self.closeLabel.text = ASLocalizedString(@"挂断");
  165. [self.chatBotoomView addSubview:self.closeLabel];
  166. _yangshengqiButton = [UIButton buttonWithType:UIButtonTypeCustom];
  167. self.yangshengqiButton.frame = CGRectMake((SCREEN_WIDTH - 70*3)/4*3+70*2, self.maikefengButton.top, 70, 70);
  168. [self.yangshengqiButton setBackgroundImage:[UIImage imageNamed:@"yangshengqiclose"] forState:UIControlStateNormal];
  169. [self.yangshengqiButton setBackgroundImage:[UIImage imageNamed:@"yangshengqiopen"] forState:UIControlStateSelected];
  170. [self.chatBotoomView addSubview:self.yangshengqiButton];
  171. [self.yangshengqiButton addTarget:self action:@selector(yangshengqiButtonClick) forControlEvents:UIControlEventTouchUpInside];
  172. _yangshengqiLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, self.maikefengButton.bottom + 10, SCREEN_WIDTH/3, 20)];
  173. self.yangshengqiLabel.centerX = self.yangshengqiButton.centerX;
  174. self.yangshengqiLabel.textAlignment = NSTextAlignmentCenter;
  175. self.yangshengqiLabel.font = [UIFont systemFontOfSize:16];
  176. self.yangshengqiLabel.textColor = [UIColor colorWithHex:0x999999];
  177. self.yangshengqiLabel.text = ASLocalizedString(@"扬声器已关");
  178. [self.chatBotoomView addSubview:self.yangshengqiLabel];
  179. }
  180. #pragma mark - 接听点击事件
  181. //是否接听,接听
  182. - (void)receiveButtonClick {
  183. WeakSelf
  184. self.isNormalChatBlock = ^(BOOL isNormal) {
  185. if (isNormal) {
  186. [weakSelf receiveChatSendMsg];
  187. return;
  188. }
  189. [AudioChatViewController destoryShareRootVC];
  190. };
  191. [self askChatIsNormal];
  192. }
  193. - (void)receiveChatSendMsg {
  194. WeakSelf
  195. SIMMsgObj *obj = [self.mChatFriend sendCustomCallAudioTextMsg:@"接听者,接听语音通话" callAudioType:AudioChatType_receive
  196. isCall:self.isZhuDongCall
  197. block:^(SResBase *resb, SIMMsgObj *newObj) {
  198. if (!resb.msuccess)
  199. {
  200. [SVProgressHUD showErrorWithStatus:resb.mmsg];
  201. } else {
  202. //发送成功了,修改UI
  203. [weakSelf joinChannel:[NSString stringWithFormat:@"%d",self.mChatFriend.mUser_id]];
  204. weakSelf.tipLabel.hidden = YES;
  205. weakSelf.chatBotoomView.hidden = NO;
  206. weakSelf.receiveBottomView.hidden = YES;
  207. [weakSelf reloadDataWithType:(AudioChatType_receive)];
  208. [weakSelf.player stop];
  209. }
  210. }];
  211. }
  212. //是否接听,挂断通话
  213. - (void)receiveCloseButtonClick {
  214. WeakSelf
  215. SIMMsgObj *obj = [self.mChatFriend sendCustomCallAudioTextMsg:@"接听者,挂断语音通话"
  216. callAudioType:AudioChatType_beidongClose
  217. isCall:self.isZhuDongCall
  218. block:^(SResBase *resb, SIMMsgObj *newObj) {
  219. if (!resb.msuccess)
  220. {
  221. [SVProgressHUD showErrorWithStatus:resb.mmsg];
  222. } else {
  223. //发送成功了,直接挂断销毁视图
  224. if (self.timesCount > 0) {
  225. if ([AudioChatTool.shareInstance.delegate respondsToSelector:@selector(sendTimes:)]){
  226. [AudioChatTool.shareInstance.delegate sendTimes:[NSString stringWithFormat:@"%@%@",ASLocalizedString(@"语音通话时间:"), self.timesLabel.text]];
  227. }
  228. // [self.mChatFriend sendTextMsg:[NSString stringWithFormat:@"%@%@",ASLocalizedString(@"语音通话时间:"), self.timesLabel.text] block:^(SResBase *resb, SIMMsgObj *thatmsg) {
  229. //
  230. // }];
  231. }
  232. [AudioChatViewController destoryShareRootVC];
  233. }
  234. }];
  235. }
  236. #pragma mark - 通话中点击事件
  237. - (void)maikeFengButtonClick {
  238. self.maikefengButton.selected = !self.maikefengButton.isSelected;
  239. if (self.maikefengButton.isSelected) {
  240. self.maikefengLabel.text = ASLocalizedString(@"麦克风已关闭");
  241. } else {
  242. self.maikefengLabel.text = ASLocalizedString(@"麦克风已开启");
  243. }
  244. [self setIsMute:self.maikefengButton.isSelected];
  245. }
  246. - (void)closeButtonClick {
  247. WeakSelf
  248. SIMMsgObj *obj = [self.mChatFriend sendCustomCallAudioTextMsg:@"发起者挂断语音通话"
  249. callAudioType:AudioChatType_zhudongClose
  250. isCall:self.isZhuDongCall
  251. block:^(SResBase *resb, SIMMsgObj *newObj) {
  252. if (!resb.msuccess)
  253. {
  254. [SVProgressHUD showErrorWithStatus:resb.mmsg];
  255. } else {
  256. if (self.timesCount > 0) {
  257. if ([AudioChatTool.shareInstance.delegate respondsToSelector:@selector(sendTimes:)]){
  258. [AudioChatTool.shareInstance.delegate sendTimes:[NSString stringWithFormat:@"%@%@",ASLocalizedString(@"语音通话时间:"), self.timesLabel.text]];
  259. }
  260. }
  261. //发送成功了,直接挂断销毁视图
  262. [AudioChatViewController destoryShareRootVC];
  263. }
  264. }];
  265. }
  266. - (void)yangshengqiButtonClick {
  267. self.yangshengqiButton.selected = !self.yangshengqiButton.isSelected;
  268. if (self.yangshengqiButton.isSelected) {
  269. self.yangshengqiLabel.text = ASLocalizedString(@"扬声器已开");
  270. } else {
  271. self.yangshengqiLabel.text = ASLocalizedString(@"扬声器已关");
  272. }
  273. [self openYangshengqi:self.yangshengqiButton.isSelected];
  274. }
  275. - (void)backBtnClick {
  276. WeakSelf
  277. [[self getPresentingViewController] dismissViewControllerAnimated:YES completion:^{
  278. [weakSelf dissmissWithSmallRoom];
  279. }];
  280. }
  281. - (UIViewController *)getPresentingViewController {
  282. NSLog(@"%s ---- %@",__FUNCTION__,self.presentingViewController);
  283. return self.presentingViewController ? self.presentingViewController : self;
  284. }
  285. #pragma mark /**最小化房间*/
  286. - (void)dissmissWithSmallRoom {
  287. __block AppDelegate *app = (AppDelegate *)[[UIApplication sharedApplication] delegate];
  288. app.hasSmallAudioVideoView = YES;
  289. // app.IsInVoiceRoom = YES;
  290. TMSmallRoomView * smallRoomView = [TMSmallRoomView sharedInstance];
  291. [smallRoomView show];
  292. @weakify(self)
  293. [smallRoomView setEnterClickBlock:^{
  294. @strongify(self)
  295. app.isInAudioVideoChatVc = YES;
  296. app.hasSmallAudioVideoView = NO;
  297. // app.IsInVoiceRoom = YES;
  298. UIWindow *window = [UIApplication sharedApplication].keyWindow;
  299. UINavigationController * nav = [[UINavigationController alloc] initWithRootViewController:[AudioChatViewController shareVoiceRoomVC]];
  300. nav.modalPresentationStyle = UIModalPresentationOverFullScreen;
  301. nav.modalTransitionStyle = UIModalTransitionStyleCoverVertical;
  302. [window.rootViewController presentViewController:nav animated:YES completion:^{}];
  303. }];
  304. }
  305. #pragma mark - ******************* 通话中,数据交互,通过消息来判断逻辑进程 *******************
  306. - (void)reloadDataWithType:(AudioChatType)chatType {
  307. //1、请求语音通话,A给B发 B收到请求也要走这里判断,改变UI
  308. if (chatType == AudioChatType_call) {
  309. //发起者
  310. if (self.isZhuDongCall) {
  311. self.receiveBottomView.hidden = YES;
  312. self.chatBotoomView.hidden = NO;
  313. self.tipLabel.hidden = NO;
  314. self.tipLabel.text = ASLocalizedString(@"等待对方接受邀请...");
  315. self.closeLabel.text = ASLocalizedString(@"取消");
  316. [self joinChannel:[IMAPlatform sharedInstance].host.userId];
  317. return;
  318. }
  319. //接收者
  320. self.receiveBottomView.hidden = NO;
  321. self.chatBotoomView.hidden = YES;
  322. self.tipLabel.hidden = NO;
  323. self.tipLabel.text = ASLocalizedString(@"邀请你语音通话");
  324. [self playRecordWithName:@"phone_ringing" type:@"mp3" playCount:-1];
  325. return;
  326. }
  327. //2、接收者接听通话(B给A发)
  328. if (chatType == AudioChatType_receive) {
  329. self.receiveBottomView.hidden = YES;
  330. self.chatBotoomView.hidden = NO;
  331. self.tipLabel.hidden = YES;
  332. self.closeLabel.text = ASLocalizedString(@"挂断");
  333. //开始计时,执行计费逻辑
  334. self.timesCount = 0;
  335. [self updateTimesLabelText];
  336. self.timesLabel.hidden = NO;
  337. return;
  338. }
  339. // /** 3、挂断通话,发起者主动挂断,A给B发 */
  340. if (chatType == AudioChatType_zhudongClose) {
  341. [self playRecordWithName:@"close" type:@"wav" playCount:0];
  342. [AudioChatViewController destoryShareRootVC];
  343. return;
  344. }
  345. /** 4、挂断电话,接收者挂断,B给A发 */
  346. if (chatType == AudioChatType_beidongClose) {
  347. //接收者挂断电话,直接结束通话
  348. [self playRecordWithName:@"close" type:@"wav" playCount:0];
  349. [AudioChatViewController destoryShareRootVC];
  350. return;
  351. }
  352. /** 5、挂断电话,接收者忙线中,语音中或者在直播间中,B给A发 */
  353. if (chatType == AudioChatType_isBusy) {
  354. [self playRecordWithName:@"close" type:@"wav" playCount:0];
  355. [[BGHUDHelper sharedInstance] tipMessage:ASLocalizedString(@"对方忙")];
  356. //刚开始就挂断,太快了,给SDK一点反应时间,晚点再销毁,不然trtc销毁不掉
  357. dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
  358. [AudioChatViewController destoryShareRootVC];
  359. });
  360. return;
  361. }
  362. /** 6、主动询问A是否在房间等着B通话,B给A发 */
  363. if (chatType == AudioChatType_askIsNormal) {
  364. if (self.isZhuDongCall == NO) {
  365. return;
  366. }
  367. //告诉A自己正常,正常进行通话
  368. WeakSelf
  369. SIMMsgObj *obj = [self.mChatFriend sendCustomCallAudioTextMsg:@"发起者挂断语音通话"
  370. callAudioType:AudioChatType_notificationChatNormal
  371. isCall:self.isZhuDongCall
  372. block:^(SResBase *resb, SIMMsgObj *newObj) {
  373. if (!resb.msuccess) {
  374. [SVProgressHUD showErrorWithStatus:resb.mmsg];
  375. }
  376. }];
  377. return;
  378. }
  379. }
  380. - (void)updateTimesLabelText {
  381. if (AppDelegate.sharedAppDelegate.isInAudioVideoChatVc == NO) {
  382. return;
  383. }
  384. self.timesCount ++;
  385. int hour = self.timesCount/60/60;
  386. NSString * hoursStr = @"00";
  387. if (hour > 9) {
  388. hoursStr = [NSString stringWithFormat:@"%d",hour];
  389. } else {
  390. hoursStr = [NSString stringWithFormat:@"0%d",hour];
  391. }
  392. int min = self.timesCount/60%60;
  393. if (self.isZhuDongCall && min > self.lastMin) {
  394. [self requestPay];
  395. }
  396. self.lastMin = min;
  397. NSString * minStr = @"00";
  398. if (min > 9) {
  399. minStr = [NSString stringWithFormat:@"%d",min];
  400. } else {
  401. minStr = [NSString stringWithFormat:@"0%d",min];
  402. }
  403. int seconds = self.timesCount%60;
  404. NSString * secondsStr = @"00";
  405. if (seconds > 9) {
  406. secondsStr = [NSString stringWithFormat:@"%d",seconds];
  407. } else {
  408. secondsStr = [NSString stringWithFormat:@"0%d",seconds];
  409. }
  410. if (hour > 0) {
  411. self.timesLabel.text = [NSString stringWithFormat:@"%@:%@:%@",hoursStr,minStr,secondsStr];
  412. } else {
  413. self.timesLabel.text = [NSString stringWithFormat:@"%@:%@",minStr,secondsStr];
  414. }
  415. //小屏的话更新时间
  416. if (AppDelegate.sharedAppDelegate.hasSmallAudioVideoView) {
  417. [TMSmallRoomView sharedInstance].timeLabel.text = self.timesLabel.text;
  418. }
  419. dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
  420. [self updateTimesLabelText];
  421. });
  422. }
  423. #pragma mark - 私聊付费,发起者调用 语音跟视频聊天为1分钟调用一次调用成功继续进行聊天,返回失败则直接断开,发起者进行调用
  424. - (void)requestPay {
  425. NSMutableDictionary *parmDict = [[NSMutableDictionary alloc] init];
  426. [parmDict setObject:@"user" forKey:@"ctl"];
  427. [parmDict setObject:@"chat_charging" forKey:@"act"];
  428. [parmDict setObject:[NSString stringWithFormat:@"%d",self.mChatFriend.mUser_id] forKey:@"other_user_id"];
  429. [parmDict setObject:@"voice_price" forKey:@"expend_type"];
  430. [parmDict setObject:@"1" forKey:@"i_type"];
  431. [parmDict setObject:[BogoNetwork shareInstance].token forKey:@"token"];
  432. WeakSelf
  433. [[NetHttpsManager manager]POSTWithParameters:parmDict SuccessBlock:^(NSDictionary *responseJson) {
  434. if ([[responseJson valueForKeyPath:@"status"]integerValue] == 1) {
  435. NSLog(@" = = = = = = = =%@",responseJson);
  436. } else if ([[responseJson valueForKeyPath:@"status"]integerValue] == 0) {
  437. //没钱或者权限不足,挂断
  438. [weakSelf closeButtonClick];
  439. }
  440. } FailureBlock:^(NSError *error) {
  441. NSLog(@" = = = = = = = == %@",error);
  442. }];
  443. }
  444. #pragma mark - ******************* 腾讯TRTC 代理方法 *******************
  445. - (void)joinChannel:(NSString *)room_id {
  446. self.trtcCloud = [TRTCCloud sharedInstance];
  447. [[TRTCCloud sharedInstance] addDelegate: self];
  448. // 主播: TRTCRoleAnchor
  449. // 观众: TRTCRoleAudience
  450. [self.trtcCloud switchRole:TRTCRoleAnchor];
  451. TRTCParams *params = [[TRTCParams alloc] init];
  452. // 以字符串房间号为例
  453. params.roomId = room_id.intValue;
  454. params.userId = [IMAPlatform sharedInstance].host.userId;
  455. // 从业务后台获取到的 UserSig
  456. params.userSig = [IMALoginParam loadFromLocal].userSig;
  457. // 替换成您的 SDKAppID
  458. params.sdkAppId = TXSDKAppID;
  459. // 根据需要指定场景,以语聊房为例
  460. [self.trtcCloud enterRoom:params appScene:TRTCAppSceneAudioCall];
  461. // TRTCAudioVolumeEvaluateParams * audioVolumeEvaluateParams = [[TRTCAudioVolumeEvaluateParams alloc] init];
  462. // //【推荐取值】推荐值:300,单位为毫秒。
  463. // audioVolumeEvaluateParams.interval = 300;
  464. // /// 【字段含义】是否开启本地人声检测。
  465. // /// 【请您注意】在 startLocalAudio 之前调用才可以生效。
  466. // audioVolumeEvaluateParams.enableVadDetection = YES;
  467. // /// 【字段含义】是否开启本地人声频率计算
  468. // audioVolumeEvaluateParams.enablePitchCalculation = YES;
  469. // /// 【字段含义】是否开启声音频谱计算。
  470. // audioVolumeEvaluateParams.enableSpectrumCalculation = YES;
  471. // [self.trtcCloud enableAudioVolumeEvaluation:YES withParams:audioVolumeEvaluateParams];
  472. [self.trtcCloud startLocalAudio:TRTCAudioQualitySpeech];
  473. }
  474. #pragma mark - 静音,默认开启
  475. - (void)setIsMute:(BOOL)isMute {
  476. if (isMute) {
  477. [self.trtcCloud muteLocalAudio:YES];
  478. return;
  479. }
  480. [self.trtcCloud muteLocalAudio:NO];
  481. }
  482. #pragma mark - 开启扬声器,默认关闭
  483. - (void)openYangshengqi:(BOOL)open {
  484. if (open) {
  485. ///使用扬声器播放(即“免提”),扬声器位于手机底部,声音偏大,适合外放音乐。
  486. [self.trtcCloud setAudioRoute:TRTCAudioModeSpeakerphone];
  487. return;
  488. }
  489. ///使用听筒播放,听筒位于手机顶部,声音偏小,适合需要保护隐私的通话场景。
  490. [self.trtcCloud setAudioRoute:TRTCAudioModeEarpiece];
  491. }
  492. // 离开房间事件回调
  493. - (void)onExitRoom:(NSInteger)reason {
  494. if (reason == 0) {
  495. NSLog(@"主动调用 exitRoom 退出房间");
  496. } else if (reason == 1) {
  497. NSLog(@"被服务器踢出当前房间");
  498. } else if (reason == 2) {
  499. NSLog(@"当前房间整个被解散");
  500. }
  501. }
  502. - (void) onEnterRoom:(NSInteger ) result {
  503. NSLog(@"onEnterRoom");
  504. if(result > 0) {
  505. //接受者进房间后,主动问一下呼叫者是否是正常状态
  506. if (self.isZhuDongCall == NO) {
  507. WeakSelf
  508. self.isNormalChatBlock = ^(BOOL isNormal) {
  509. if (isNormal == NO) {
  510. [weakSelf closeButtonClick];
  511. }
  512. };
  513. [self askChatIsNormal];
  514. }
  515. } else {
  516. // [BGHUDHelper alert:[NSString stringWithFormat:@"进入直播间直播-%ld",result]];
  517. }
  518. }
  519. - (void)askChatIsNormal {
  520. WeakSelf
  521. SIMMsgObj *obj = [self.mChatFriend sendCustomCallAudioTextMsg:@"接听者,忙线中" callAudioType:AudioChatType_askIsNormal
  522. isCall:self.isZhuDongCall
  523. block:^(SResBase *resb, SIMMsgObj *newObj) {
  524. if (!resb.msuccess)
  525. {
  526. [SVProgressHUD showErrorWithStatus:resb.mmsg];
  527. } else {
  528. //1秒后,如果呼叫者没有回复说自己正常,那就退出房间
  529. dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
  530. if (weakSelf.callIsNormal && weakSelf.isNormalChatBlock) {
  531. weakSelf.isNormalChatBlock(weakSelf.callIsNormal);
  532. } else {
  533. [weakSelf judjeAskChatIsNormalBackCount:0];
  534. }
  535. });
  536. }
  537. }];
  538. }
  539. - (void)judjeAskChatIsNormalBackCount:(int)count {
  540. count ++;
  541. if (count > 10) {
  542. if (self.isNormalChatBlock) {
  543. self.isNormalChatBlock(self.callIsNormal);
  544. }
  545. return;
  546. }
  547. if (self.callIsNormal) {
  548. if (self.isNormalChatBlock) {
  549. self.isNormalChatBlock(self.callIsNormal);
  550. }
  551. return;
  552. }
  553. dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
  554. [self judjeAskChatIsNormalBackCount:count];
  555. });
  556. }
  557. - (void)onRemoteUserLeaveRoom:(NSString *)userId reason:(NSInteger)reason {
  558. //有人异常退出,可能不是正常退出的,自己也退出,不聊了
  559. //,直接挂断销毁视图
  560. [AudioChatViewController destoryShareRootVC];
  561. NSLog(@"%@", [NSString stringWithFormat:@"用户离开%@",userId]);
  562. }
  563. //功能描述:音量大小的反馈回调
  564. - (void)onUserVoiceVolume:(NSArray<TRTCVolumeInfo *> *)userVolumes totalVolume:(NSInteger)totalVolume {
  565. /*bug:当a用户在麦上正在说话时,切换到无网状态,此时虽然还显示在麦上(im还没下线),
  566. 但观众席听不到声音,光圈还在闪烁
  567. 原因: 这时观众席speakers 里面找不到a,就不会进入for循环,就不会更新a的声音为0
  568. 解决: 1先找到 麦上的用户 2去判断有无声音
  569. */
  570. // NSMutableArray<Wheat_Type_List *> *wheat_type_list = [NSMutableArray arrayWithArray:self.voiceRoomVC.roomModel.wheat_type_list];
  571. //
  572. // for (int i = 0; i < wheat_type_list.count; i ++) {
  573. //
  574. // Wheat_Type_List *info = wheat_type_list[i];
  575. //
  576. // if (info.even_wheat.user_id) {
  577. //
  578. // BOOL online = NO;
  579. //
  580. //// for (AgoraRtcAudioVolumeInfo *speaker in speakers) {
  581. // for (TRTCVolumeInfo * volumeInfo in userVolumes) {
  582. //
  583. // NSString *uid = @"";
  584. // if (volumeInfo.userId.intValue == 0) {
  585. // uid = [IMAPlatform sharedInstance].host.userId;
  586. // online = YES;
  587. // }else if (info.even_wheat.user_id == volumeInfo.userId.intValue){
  588. // uid = [NSString stringWithFormat:@"%@",volumeInfo.userId];
  589. // online = YES;
  590. // }
  591. // if (online) {
  592. // info.totalVolume = volumeInfo.volume;
  593. // // [self.users updateUser:uid volume:speaker.volume];
  594. // }
  595. // }
  596. //
  597. // wheat_type_list[i] = info;
  598. //
  599. // // if (!online) {
  600. // // [self.users updateUser:info.user_id volume:0];
  601. // // }
  602. // }
  603. // }
  604. // self.voiceRoomVC.roomModel.wheat_type_list = wheat_type_list;
  605. // [self.voiceRoomVC setRoomModel:self.voiceRoomVC.roomModel];
  606. // [self.uiController.micView setUsers:self.users];
  607. }
  608. #pragma mark - ******************* 腾讯TRTC 代理方法 end *******************
  609. #pragma mark 解决不能调为最小音量问题
  610. - (void)volumeChanged:(NSNotification *)noti
  611. {
  612. NSDictionary *tmpDict = noti.userInfo;
  613. if (tmpDict && [tmpDict isKindOfClass:[NSDictionary class]])
  614. {
  615. // if ([[tmpDict toString:@"AVSystemController_AudioVolumeChangeReasonNotificationParameter"] isEqualToString:@"ExplicitVolumeChange"] && !_isMuted)
  616. if ([[tmpDict toString:@"AVSystemController_AudioVolumeChangeReasonNotificationParameter"] isEqualToString:@"ExplicitVolumeChange"])
  617. {
  618. float volume = [[tmpDict objectForKey:@"AVSystemController_AudioVolumeNotificationParameter"] floatValue];
  619. if (volume <= 0.062500)
  620. {
  621. // [_publishController.txLivePublisher setMute:YES];
  622. }
  623. else
  624. {
  625. // [_publishController.txLivePublisher setMute:NO];
  626. }
  627. }
  628. }
  629. }
  630. #pragma mark - ************** 播放声音 ************
  631. /**播放录音*/
  632. -(void)playRecordWithName:(NSString *)musicName type:(NSString *)musicType playCount:(int)count {
  633. NSString *audioFilePath = [[NSBundle mainBundle] pathForResource:musicName ofType:musicType];
  634. NSURL *audioFileURL = [NSURL fileURLWithPath:audioFilePath];
  635. AVAudioSession *session = [AVAudioSession sharedInstance];
  636. NSError *sessionError;
  637. //AVAudioSessionCategoryPlayAndRecord,这个确保了既能录音也能播放
  638. [session setCategory:AVAudioSessionCategoryPlayback error:&sessionError];
  639. if (session == nil) {
  640. NSLog(@"Error creating sessing:%@", [sessionError description]);
  641. } else {
  642. [session setActive:YES error:nil];
  643. }
  644. NSError *playError;
  645. self.player = [[AVAudioPlayer alloc]initWithContentsOfURL:audioFileURL error:&playError];
  646. self.player.numberOfLoops = count;
  647. // self.player.volume = 20;
  648. //当播放录音为空, 打印错误信息
  649. if (self.player == nil) {
  650. NSLog(@"Error crenting player: %@", [playError description]);
  651. }
  652. self.player.delegate = self;
  653. if ([self.player isPlaying]) {
  654. [self.player pause];
  655. } else {
  656. [self.player play];
  657. }
  658. }
  659. - (void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)player successfully:(BOOL)flag {
  660. // self.player = nil;
  661. NSLog(@"播放完成");
  662. // [self playRecord];
  663. }
  664. @end