| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985 |
- //
- // NTESNetChatViewController.m
- // NIM
- //
- // Created by chris on 15/5/18.
- // Copyright (c) 2015年 Netease. All rights reserved.
- //
- #import "NTESNetChatViewController.h"
- #import "UIAlertView+NTESBlock.h"
- #import "UIView+Toast.h"
- #import "NTESTimerHolder.h"
- #import "NTESNetCallChatInfo.h"
- #import "NTESBundleSetting.h"
- #import <AVFoundation/AVFoundation.h>
- #import <AssetsLibrary/ALAssetsLibrary.h>
- #import <Photos/Photos.h>
- #import "UIView+NTES.h"
- //十秒之后如果还是没有收到对方响应的control字段,则自己发起一个假的control,用来激活铃声并自己先进入房间
- #define DelaySelfStartControlTime 10
- //激活铃声后无人接听的超时时间
- #define NoBodyResponseTimeOut 45
- //周期性检查剩余磁盘空间
- #define DiskCheckTimeInterval 10
- //剩余磁盘空间不足的警告阈值
- #define MB (1024ll * 1024ll)
- #define FreeDiskSpaceWarningThreshold (10 * MB)
- @interface NTESNetChatViewController ()
- @property(nonatomic, strong) NTESTimerHolder *timer;
- @property(nonatomic, strong) NSMutableArray *chatRoom;
- @property(nonatomic, assign) BOOL recordWillStopForLackSpace;
- @property(nonatomic, strong) NTESTimerHolder *diskCheckTimer;
- @property(nonatomic, assign) BOOL userHangup;
- @property(nonatomic, strong) NTESTimerHolder *calleeResponseTimer; //被叫等待用户响应接听或者拒绝的时间
- @property(nonatomic, assign) BOOL calleeResponsed;
- @property(nonatomic, assign) int successRecords;
- //@property (nonatomic, strong) NTESRecordSelectView * recordView;
- @end
- @implementation NTESNetChatViewController {
- UInt64 CallId;
- }
- - (BOOL)forbidInteractivePop {
- return YES;
- }
- - (instancetype)initWithCallee:(NSString *)callee {
- self = [self initWithNibName:nil bundle:nil];
- if (self) {
- self.peerUid = callee;
- self.callInfo.callee = callee;
- self.callInfo.caller = [[NIMSDK sharedSDK].loginManager currentAccount];
- }
- return self;
- }
- - (instancetype)initWithCaller:(NSString *)caller callId:(uint64_t)callID {
- self = [self initWithNibName:nil bundle:nil];
- if (self) {
- self.peerUid = caller;
- self.callInfo.caller = caller;
- self.callInfo.callee = [[NIMSDK sharedSDK].loginManager currentAccount];
- self.callInfo.callID = callID;
- }
- return self;
- }
- - (instancetype)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
- self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
- if (self) {
- self.edgesForExtendedLayout = UIRectEdgeAll;
- if (!self.callInfo) {
- [[NIMSDK sharedSDK].mediaManager switchAudioOutputDevice:NIMAudioOutputDeviceSpeaker];
- _callInfo = [[NTESNetCallChatInfo alloc] init];
- }
- _timer = [[NTESTimerHolder alloc] init];
- _diskCheckTimer = [[NTESTimerHolder alloc] init];
- //防止应用在后台状态,此时呼入,会走init但是不会走viewDidLoad,此时呼叫方挂断,导致被叫监听不到,界面无法消去的问题。
- id <NIMNetCallManager> manager = [NIMAVChatSDK sharedSDK].netCallManager;
- [manager addDelegate:self];
- }
- return self;
- }
- - (void)dealloc {
- NSLog(@"vc dealloc info : %@", self);
- [[NIMAVChatSDK sharedSDK].netCallManager removeDelegate:self];
- }
- - (void)viewDidLoad {
- [super viewDidLoad];
- __weak typeof(self) wself = self;
- [[NIMAVChatSDK sharedSDK].netCallManager addDelegate:self];
- [self checkServiceEnable:^(BOOL result) {
- if (result) {
- // [self response:YES];
- [wself afterCheckService];
- } else {
- //用户禁用服务,干掉界面
- if (wself.callInfo.callID) {
- //说明是被叫方
- [[NIMAVChatSDK sharedSDK].netCallManager response:wself.callInfo.callID accept:NO option:nil completion:nil];
- }
- [wself dismiss:nil];
- }
- }];
- }
- - (void)viewWillAppear:(BOOL)animated {
- [super viewWillAppear:animated];
- }
- - (void)viewDidAppear:(BOOL)animated {
- [super viewDidAppear:animated];
- [UIApplication sharedApplication].idleTimerDisabled = YES;
- }
- - (void)viewWillDisappear:(BOOL)animated {
- [super viewWillDisappear:animated];
- [self.player stop];
- // [[NIMAVChatSDK sharedSDK].netCallManager hangup:CallId];
- [UIApplication sharedApplication].idleTimerDisabled = NO;
- }
- - (void)afterCheckService {
- if (self.callInfo.isStart) {
- [self.timer startTimer:0.5 delegate:self repeats:YES];
- [self onCalling];
- } else if (self.callInfo.callID) {
- [self startByCallee];
- } else {
- [self startByCaller];
- }
- [self checkFreeDiskSpace];
- [self.diskCheckTimer startTimer:DiskCheckTimeInterval
- delegate:self
- repeats:YES];
- }
- #pragma mark - Subclass Impl
- - (void)startByCaller {
- if (self.callInfo.callType == NIMNetCallTypeVideo) {
- //视频呼叫马上发起
- [self doStartByCaller];
- } else {
- //语音呼叫先播放一断提示音,然后再发起
- [self playConnnetRing];
- __weak typeof(self) wself = self;
- dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t) (3.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
- if (!wself) {
- return;
- }
- if (wself.userHangup) {
- NSLog(@"Netcall request was cancelled before, ignore it.");
- return;
- }
- [wself doStartByCaller];
- });
- }
- }
- - (void)doStartByCaller {
- self.callInfo.isStart = YES;
- NSArray *callees = [NSArray arrayWithObjects:self.callInfo.callee, nil];
- NIMNetCallOption *option = [[NIMNetCallOption alloc] init];
- option.extendMessage = @"音视频请求扩展信息";
- option.apnsContent = [NSString stringWithFormat:@"%@请求", self.callInfo.callType == NIMNetCallTypeAudio ? @"网络通话" : @"视频聊天"];
- // option.apnsInuse = NO;
- option.apnsSound = @"video_chat_push.mp3";
- [self fillUserSetting:option];
- option.videoCaptureParam.startWithCameraOn = (self.callInfo.callType == NIMNetCallTypeVideo);
- __weak typeof(self) wself = self;
- [[NIMAVChatSDK sharedSDK].netCallManager start:callees type:wself.callInfo.callType option:option completion:^(NSError *error, UInt64 callID) {
- if (!error && wself) {
- NSLog(@"呼叫成功");
- CallId = callID;
- wself.callInfo.callID = callID;
- wself.chatRoom = [[NSMutableArray alloc] init];
- //十秒之后如果还是没有收到对方响应的control字段,则自己发起一个假的control,用来激活铃声并自己先进入房间
- NSTimeInterval delayTime = DelaySelfStartControlTime;
- dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t) (delayTime * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
- [wself onControl:callID from:wself.callInfo.callee type:NIMNetCallControlTypeFeedabck];
- });
- } else {
- NSLog(@"呼叫失败");
- if (error) {
- NSLog(@"连接失败跳转%@", error);
- [wself.navigationController.view makeToast:@"连接失败"
- duration:2
- position:CSToastPositionCenter];
- } else {
- //说明在start的过程中把页面关了。。
- [[NIMAVChatSDK sharedSDK].netCallManager hangup:callID];
- }
- [wself dismiss:nil];
- }
- }];
- }
- - (void)startByCallee {
- //告诉对方可以播放铃声了
- self.callInfo.isStart = YES;
- NSMutableArray *room = [[NSMutableArray alloc] init];
- [room addObject:self.callInfo.caller];
- self.chatRoom = room;
- [[NIMAVChatSDK sharedSDK].netCallManager control:self.callInfo.callID type:NIMNetCallControlTypeFeedabck];
- [self playReceiverRing];
- _calleeResponseTimer = [[NTESTimerHolder alloc] init];
- [_calleeResponseTimer startTimer:NoBodyResponseTimeOut delegate:self repeats:NO];
- }
- - (void)hangup {
- _userHangup = YES;
- [[NIMAVChatSDK sharedSDK].netCallManager hangup:self.callInfo.callID];
- if (self.callInfo.localRecording) {
- __weak typeof(self) wself = self;
- dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t) (2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
- wself.chatRoom = nil;
- [wself dismiss:nil];
- });
- } else {
- self.chatRoom = nil;
- [self dismiss:nil];
- }
- }
- - (void)response:(BOOL)accept {
- _calleeResponsed = YES;
- NIMNetCallOption *option = [[NIMNetCallOption alloc] init];
- [self fillUserSetting:option];
- __weak typeof(self) wself = self;
- [[NIMAVChatSDK sharedSDK].netCallManager response:self.callInfo.callID accept:accept option:option completion:^(NSError *error, UInt64 callID) {
- if (!error) {
- NSLog(@"被接成功");
- [wself onCalling];
- [wself.player stop];
- [wself.chatRoom addObject:wself.callInfo.callee];
- NSTimeInterval delay = 10.f; //10秒后判断下房间
- dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t) (delay * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
- if (wself.chatRoom.count == 1) {
- [wself.navigationController.view makeToast:@"通话失败"
- duration:2
- position:CSToastPositionCenter];
- [wself hangup];
- }
- });
- } else {
- NSLog(@"被接失败");
- wself.chatRoom = nil;
- [wself.navigationController.view makeToast:@"连接失败"
- duration:2
- position:CSToastPositionCenter];
- [wself dismiss:nil];
- }
- }];
- //dismiss需要放在self后面,否在ios7下会有野指针
- if (accept) {
- [self waitForConnectiong];
- } else {
- [self dismiss:nil];
- }
- }
- //- (void)onReceive:(UInt64)callID from:(NSString *)caller type:(NIMNetCallMediaType)type message:(NSString *)extendMessage{
- //
- //// NTESMainTabController *tabVC = [NTESMainTabController instance];
- //// [tabVC.view endEditing:YES];
- //// UINavigationController *nav = tabVC.selectedViewController;
- ////
- //// if ([self shouldResponseBusy]){
- //// [[NIMAVChatSDK sharedSDK].netCallManager control:callID type:NIMNetCallControlTypeBusyLine];
- //// }
- //// else {
- ////
- //// if ([self shouldFireNotification:caller]) {
- //// NSString *text = [self textByCaller:caller
- //// type:type];
- //// [_notifier start:text];
- //// }
- //
- //
- //
- // UIViewController *vc;
- // switch (type) {
- // case NIMNetCallTypeVideo:{
- // vc = [[NTESNetChatViewController alloc] initWithCaller:caller callId:callID];
- //// [self response:NO];
- // }
- // break;
- // case NIMNetCallTypeAudio:{
- //// vc = [[NTESAudioChatViewController alloc] initWithCaller:caller callId:callID];
- // }
- // break;
- // default:
- // break;
- // }
- // if (!vc) {
- // return;
- // }
- //
- // // 由于音视频聊天里头有音频和视频聊天界面的切换,直接用present的话页面过渡会不太自然,这里还是用push,然后做出present的效果
- //// CATransition *transition = [CATransition animation];
- //// transition.duration = 0.25;
- //// transition.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionDefault];
- //// transition.type = kCATransitionPush;
- //// transition.subtype = kCATransitionFromTop;
- //// [nav.view.layer addAnimation:transition forKey:nil];
- //// nav.navigationBarHidden = YES;
- //// if (nav.presentedViewController) {
- //// // fix bug MMC-1431
- //// [nav.presentedViewController dismissViewControllerAnimated:NO completion:nil];
- //// }
- //// [nav pushViewController:vc animated:NO];
- //// }
- //}
- - (void)dismiss:(void (^)(void))completion {
- [self dismissViewControllerAnimated:YES completion:^{
- if (completion) {
- completion();
- }
- }];
- }
- - (void)onCalling {
- //子类重写
- }
- - (void)waitForConnectiong {
- //子类重写
- }
- - (void)onCalleeBusy {
- //子类重写
- }
- - (BOOL)startAudioRecording {
- UInt64 timestamp = [[NSDate date] timeIntervalSince1970] * 1000;
- NSString *pathComponent = [NSString stringWithFormat:@"record_audio%@_%llu", [[NIMSDK sharedSDK].loginManager currentAccount], timestamp];
- NSURL *filePath = [[[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject] URLByAppendingPathComponent:pathComponent];
- return [[NIMAVChatSDK sharedSDK].netCallManager startAudioRecording:filePath error:nil];
- }
- - (BOOL)startLocalRecording {
- UInt64 timestamp = [[NSDate date] timeIntervalSince1970] * 1000;
- NSString *pathComponent = [NSString stringWithFormat:@"record_%@_%llu.mp4", [[NIMSDK sharedSDK].loginManager currentAccount], timestamp];
- NSURL *filePath = [[[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject] URLByAppendingPathComponent:pathComponent];
- BOOL startAccepted;
- startAccepted = [[NIMAVChatSDK sharedSDK].netCallManager startRecording:filePath
- videoBitrate:(UInt32) [[NTESBundleSetting sharedConfig] localRecordVideoKbps] * 1000
- uid:[[NIMSDK sharedSDK].loginManager currentAccount]
- ];
- return startAccepted;
- }
- - (BOOL)startOtherSideRecording {
- UInt64 timestamp = [[NSDate date] timeIntervalSince1970] * 1000;
- NSString *pathComponent = [NSString stringWithFormat:@"record_%@_%llu.mp4", self.peerUid, timestamp];
- NSURL *filePath = [[[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject] URLByAppendingPathComponent:pathComponent];
- BOOL startAccepted;
- startAccepted = [[NIMAVChatSDK sharedSDK].netCallManager startRecording:filePath
- videoBitrate:(UInt32) [[NTESBundleSetting sharedConfig] localRecordVideoKbps] * 1000
- uid:self.peerUid
- ];
- return startAccepted;
- }
- - (void)stopAudioRecording {
- [[NIMAVChatSDK sharedSDK].netCallManager stopAudioRecording];
- self.callInfo.audioConversation = NO;
- }
- - (BOOL)stopLocalRecording {
- return [[NIMAVChatSDK sharedSDK].netCallManager stopRecordingWithUid:[[NIMSDK sharedSDK].loginManager currentAccount]];
- }
- - (BOOL)stopOtherSideRecording {
- return [[NIMAVChatSDK sharedSDK].netCallManager stopRecordingWithUid:self.peerUid];
- }
- - (void)udpateLowSpaceWarning:(BOOL)show {
- //子类重写
- }
- - (void)recordWithAudioConversation:(BOOL)audioConversationOn myMedia:(BOOL)myMediaOn otherSideMedia:(BOOL)otherSideMediaOn video:(BOOL)isVideo {
- NSString *toastText = @"";
- int records = 0;
- _successRecords = 0;//不包括语音对话
- //语音对话
- if (audioConversationOn) {
- records++;
- if (!self.callInfo.audioConversation) {
- toastText = @"语音对话开始失败";
- }
- }
- //自己音视频
- if (myMediaOn) {
- records++;
- if (![self startLocalRecording]) {
- if (isVideo) {
- toastText = [toastText stringByAppendingString:[toastText isEqualToString:@""] ? @"自己音视频开始失败" : @",自己音视频开始失败"];
- } else {
- toastText = [toastText stringByAppendingString:[toastText isEqualToString:@""] ? @"自己音频开始失败" : @",自己音频开始失败"];
- }
- } else
- _successRecords++;
- }
- //对方音视频
- if (otherSideMediaOn) {
- records++;
- if (![self startOtherSideRecording]) {
- if (isVideo) {
- toastText = [toastText stringByAppendingString:[toastText isEqualToString:@""] ? @"对方音视频开始失败" : @",对方音视频开始失败"];
- } else {
- toastText = [toastText stringByAppendingString:[toastText isEqualToString:@""] ? @"对方音频开始失败" : @",对方音频开始失败"];
- }
- } else
- _successRecords++;
- }
- //判断是否需要提示
- if (![toastText isEqualToString:@""]) {
- if ([toastText componentsSeparatedByString:@","].count == records) {
- [self.view makeToast:@"开始录制失败"
- duration:2
- position:CSToastPositionCenter];
- } else {
- [self.view makeToast:toastText
- duration:2
- position:CSToastPositionCenter];
- }
- }
- }
- - (void)stopRecordTaskWithVideo:(BOOL)isVideo {
- NSString *toastText = @"";
- int records = 0;
- //结束自己音视频
- if (self.callInfo.localRecording) {
- records++;
- if (![self stopLocalRecording]) {
- if (isVideo) {
- toastText = [toastText stringByAppendingString:[toastText isEqualToString:@""] ? @"自己音视频结束失败" : @",自己音视频结束失败"];
- } else {
- toastText = [toastText stringByAppendingString:[toastText isEqualToString:@""] ? @"自己音频结束失败" : @",自己音频结束失败"];
- }
- }
- }
- //结束对方音视频
- if (self.callInfo.otherSideRecording) {
- records++;
- if (![self stopOtherSideRecording]) {
- if (isVideo) {
- toastText = [toastText stringByAppendingString:[toastText isEqualToString:@""] ? @"对方音视频结束失败" : @",对方音视频结束失败"];
- } else {
- toastText = [toastText stringByAppendingString:[toastText isEqualToString:@""] ? @"对方音频结束失败" : @",对方音频结束失败"];
- }
- }
- }
- //判断是否要提示
- if (![toastText isEqualToString:@""]) {
- if ([toastText componentsSeparatedByString:@","].count == records) {
- [self.view makeToast:@"结束录制失败"
- duration:3
- position:CSToastPositionCenter];
- } else {
- [self.view makeToast:toastText
- duration:3
- position:CSToastPositionCenter];
- }
- }
- }
- - (BOOL)allRecordsStopped {
- //当前没有录制任务
- if (!self.callInfo.localRecording && !self.callInfo.otherSideRecording && !self.callInfo.audioConversation) {
- return YES;
- } else {
- return NO;
- }
- }
- - (BOOL)allRecordsSucceeed {
- int num = self.callInfo.localRecording + self.callInfo.otherSideRecording;
- if (num == _successRecords) {
- return YES;
- } else {
- return NO;
- }
- }
- - (NSString *)peerUid {
- if (_peerUid) {
- return _peerUid;
- } else {
- if ([_callInfo.callee isEqualToString:[[NIMSDK sharedSDK].loginManager currentAccount]]) {
- _peerUid = _callInfo.caller;
- return _callInfo.caller;
- } else {
- _peerUid = _callInfo.callee;
- return _callInfo.callee;
- }
- }
- }
- //-(void)showRecordSelectView:(BOOL)isVideo
- //{
- // if (!_recordView) {
- // _recordView = [[NTESRecordSelectView alloc]initWithFrame:CGRectMake(0, 0, 250, 250) Video:isVideo];
- // _recordView.delegate = self;
- // _recordView.centerX = self.view.width/2;
- // _recordView.centerY = self.view.height/2;
- // }
- // [self.view addSubview:_recordView];
- //}
- #pragma mark - NIMNetCallManagerDelegate
- - (void)onControl:(UInt64)callID
- from:(NSString *)user
- type:(NIMNetCallControlType)control {
- if (user == [[NIMSDK sharedSDK].loginManager currentAccount]) {
- //多端登录时,自己会收到自己发出的控制指令,这里忽略他
- return;
- }
- if (callID != self.callInfo.callID) {
- return;
- }
- switch (control) {
- case NIMNetCallControlTypeFeedabck: {
- NSMutableArray *room = self.chatRoom;
- if (room && !room.count && !_userHangup) {
- [self playSenderRing];
- [room addObject:self.callInfo.caller];
- //40秒之后查看一下房间状态,如果房间还在一个人的话,就播放铃声超时
- __weak typeof(self) wself = self;
- uint64_t callId = self.callInfo.callID;
- NSTimeInterval delayTime = NoBodyResponseTimeOut;
- dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t) (delayTime * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
- NSMutableArray *room = wself.chatRoom;
- if (wself && room && room.count == 1) {
- [[NIMAVChatSDK sharedSDK].netCallManager hangup:callId];
- wself.chatRoom = nil;
- [wself playTimeoutRing];
- [wself.navigationController.view makeToast:@"无人接听"
- duration:2
- position:CSToastPositionCenter];
- [wself startChat];
- [wself dismiss:nil];
- }
- });
- }
- break;
- }
- case NIMNetCallControlTypeBusyLine: {
- [self onCalleeBusy];
- [self playOnCallRing];
- _userHangup = YES;
- [[NIMAVChatSDK sharedSDK].netCallManager hangup:callID];
- __weak typeof(self) wself = self;
- dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t) (3.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
- [wself startChat];
- [wself dismiss:nil];
- });
- break;
- }
- case NIMNetCallControlTypeStartRecord:
- [self.view makeToast:@"对方开始了录制"
- duration:1
- position:CSToastPositionCenter];
- break;
- case NIMNetCallControlTypeStopRecord:
- [self.view makeToast:@"对方结束了录制"
- duration:1
- position:CSToastPositionCenter];
- break;
- default:
- break;
- }
- }
- - (void)onResponse:(UInt64)callID from:(NSString *)callee accepted:(BOOL)accepted {
- if (self.callInfo.callID == callID) {
- if (!accepted) {
- self.chatRoom = nil;
- [self.navigationController.view makeToast:@"对方拒绝接听"
- duration:2
- position:CSToastPositionCenter];
- [self playHangUpRing];
- __weak typeof(self) wself = self;
- dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t) (3.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
- [wself startChat];
- [wself dismiss:nil];
- });
- } else {
- [self.player stop];
- [self onCalling];
- [self.chatRoom addObject:callee];
- }
- }
- }
- - (void)onCallEstablished:(UInt64)callID {
- if (self.callInfo.callID == callID) {
- self.callInfo.startTime = [NSDate date].timeIntervalSince1970;
- [self.timer startTimer:0.5 delegate:self repeats:YES];
- }
- }
- - (void)onCallDisconnected:(UInt64)callID withError:(NSError *)error {
- if (self.callInfo.callID == callID) {
- [self.timer stopTimer];
- [self dismiss:nil];
- self.chatRoom = nil;
- }
- }
- - (void)onResponsedByOther:(UInt64)callID
- accepted:(BOOL)accepted {
- [self.view.window makeToast:@"已在其他端处理"
- duration:2
- position:CSToastPositionCenter];
- [self dismiss:nil];
- }
- - (void)onHangup:(UInt64)callID
- by:(NSString *)user {
- if (self.callInfo.callID == callID) {
- [self.player stop];
- if (self.callInfo.localRecording) {
- __weak typeof(self) wself = self;
- dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t) (2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
- [wself dismiss:nil];
- });
- } else {
- [self dismiss:nil];
- }
- }
- }
- - (void)onRecordStarted:(UInt64)callID fileURL:(NSURL *)fileURL uid:(NSString *)userId {
- if (self.callInfo.callID == callID) {
- if ([userId isEqualToString:[[NIMSDK sharedSDK].loginManager currentAccount]]) {
- self.callInfo.localRecording = YES;
- }
- if ([userId isEqualToString:self.peerUid]) {
- self.callInfo.otherSideRecording = YES;
- }
- }
- }
- - (void)onRecordError:(NSError *)error
- callID:(UInt64)callID
- uid:(NSString *)userId {
- NSLog(@"Local record error %@ (%zd)", error.localizedDescription, error.code);
- if (self.callInfo.callID == callID) {
- [self.view makeToast:[NSString stringWithFormat:@"录制发生错误: %zd", error.code]
- duration:2
- position:CSToastPositionCenter];
- if ([userId isEqualToString:[[NIMSDK sharedSDK].loginManager currentAccount]]) {
- self.callInfo.localRecording = NO;
- }
- if ([userId isEqualToString:self.peerUid]) {
- self.callInfo.otherSideRecording = NO;
- }
- }
- if (error.code == NIMAVLocalErrorCodeRecordWillStopForLackSpace) {
- _recordWillStopForLackSpace = YES;
- }
- }
- - (void)onRecordStopped:(UInt64)callID
- fileURL:(NSURL *)fileURL
- uid:(NSString *)userId {
- if (self.callInfo.callID == callID) {
- if ([userId isEqualToString:[[NIMSDK sharedSDK].loginManager currentAccount]]) {
- self.callInfo.localRecording = NO;
- }
- if ([userId isEqualToString:self.peerUid]) {
- self.callInfo.otherSideRecording = NO;
- }
- //辅助验证: 写到系统相册
- [self requestAuthorizationSaveToPhotosAlbum:fileURL];
- }
- }
- #pragma mark - NTESRecordSelectViewDelegate
- - (void)onRecordWithAudioConversation:(BOOL)audioConversationOn myMedia:(BOOL)myMediaOn otherSideMedia:(BOOL)otherSideMediaOn {
- //子类重写
- }
- #pragma mark - M80TimerHolderDelegate
- - (void)onNTESTimerFired:(NTESTimerHolder *)holder {
- if (holder == self.diskCheckTimer) {
- [self checkFreeDiskSpace];
- } else if (holder == self.calleeResponseTimer) {
- if (!_calleeResponsed) {
- [self.navigationController.view makeToast:@"接听超时"
- duration:2
- position:CSToastPositionCenter];
- [self response:NO];
- }
- }
- }
- #pragma mark - Misc
- - (void)checkServiceEnable:(void (^)(BOOL))result {
- if ([[AVAudioSession sharedInstance] respondsToSelector:@selector(requestRecordPermission:)]) {
- [[AVAudioSession sharedInstance] performSelector:@selector(requestRecordPermission:) withObject:^(BOOL granted) {
- dispatch_async_main_safe(^{
- if (granted) {
- NSString *mediaType = AVMediaTypeVideo;
- AVAuthorizationStatus authStatus = [AVCaptureDevice authorizationStatusForMediaType:mediaType];
- if (authStatus == AVAuthorizationStatusRestricted || authStatus == AVAuthorizationStatusDenied) {
- UIAlertView *alert = [[UIAlertView alloc] initWithTitle:nil
- message:@"相机权限受限,无法视频聊天"
- delegate:nil
- cancelButtonTitle:@"确定"
- otherButtonTitles:nil];
- [alert showAlertWithCompletionHandler:^(NSInteger idx) {
- if (result) {
- result(NO);
- }
- }];
- } else {
- if (result) {
- result(YES);
- }
- }
- } else {
- UIAlertView *alert = [[UIAlertView alloc] initWithTitle:nil
- message:@"麦克风权限受限,无法聊天"
- delegate:nil
- cancelButtonTitle:@"确定"
- otherButtonTitles:nil];
- [alert showAlertWithCompletionHandler:^(NSInteger idx) {
- if (result) {
- result(NO);
- }
- }];
- }
- });
- }];
- }
- }
- - (UIStatusBarStyle)preferredStatusBarStyle {
- return UIStatusBarStyleLightContent;
- }
- - (void)requestAuthorizationSaveToPhotosAlbum:(NSURL *)fileURL {
- __weak typeof(self) wself = self;
- if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 8.0) {
- [PHPhotoLibrary requestAuthorization:^(PHAuthorizationStatus status) {
- if (status == PHAuthorizationStatusRestricted || status == PHAuthorizationStatusDenied) {
- //没有权限
- dispatch_async_main_safe(^{
- [wself.navigationController.view makeToast:@"保存失败,没有相册权限"
- duration:3
- position:CSToastPositionCenter];
- });
- } else if (status == PHAuthorizationStatusAuthorized) {
- //有权限
- [wself saveToPhotosAlbum:fileURL];
- }
- }];
- } else {
- [self saveToPhotosAlbum:fileURL];
- }
- }
- - (void)saveToPhotosAlbum:(NSURL *)fileURL {
- if (fileURL) {
- __weak typeof(self) wself = self;
- if ([[[UIDevice currentDevice] systemVersion] floatValue] < 8.0) {
- ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init];
- [library writeVideoAtPathToSavedPhotosAlbum:fileURL
- completionBlock:^(NSURL *assetURL, NSError *error) {
- [wself checkVideoSaveToAlbum:error];
- }];
- } else {
- [[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{
- [PHAssetChangeRequest creationRequestForAssetFromVideoAtFileURL:fileURL];
- }
- completionHandler:^(BOOL success, NSError *_Nullable error) {
- dispatch_async_main_safe(^{
- [wself checkVideoSaveToAlbum:error];
- });
- }];
- }
- }
- }
- - (void)checkVideoSaveToAlbum:(NSError *)error {
- NSString *toast = _recordWillStopForLackSpace ? @"你的手机内存不足,录制已结束\n" : @"录制已结束\n";
- if (error) {
- toast = [NSString stringWithFormat:@"%@保存至系统相册失败:%zd", toast, error.code];
- } else {
- toast = [toast stringByAppendingString:@"录制文件已保存至系统相册"];
- }
- if (!self.callInfo.localRecording && !self.callInfo.otherSideRecording && _successRecords == 1) {
- [self.navigationController.view makeToast:toast
- duration:3
- position:CSToastPositionCenter];
- }
- _successRecords--;
- }
- - (void)checkFreeDiskSpace {
- if (self.callInfo.localRecording) {
- uint64_t freeSpace = 1000 * MB;
- NSError *error;
- NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
- NSDictionary *attrbites = [[NSFileManager defaultManager] attributesOfFileSystemForPath:[paths lastObject] error:&error];
- if (attrbites) {
- NSNumber *freeFileSystemSizeInBytes = [attrbites objectForKey:NSFileSystemFreeSize];
- freeSpace = [freeFileSystemSizeInBytes unsignedLongLongValue];
- [self udpateLowSpaceWarning:(freeSpace < FreeDiskSpaceWarningThreshold)];
- }
- }
- }
- - (void)fillUserSetting:(NIMNetCallOption *)option {
- option.autoRotateRemoteVideo = [[NTESBundleSetting sharedConfig] videochatAutoRotateRemoteVideo];
- option.serverRecordAudio = [[NTESBundleSetting sharedConfig] serverRecordAudio];
- option.serverRecordVideo = [[NTESBundleSetting sharedConfig] serverRecordVideo];
- option.preferredVideoEncoder = [[NTESBundleSetting sharedConfig] perferredVideoEncoder];
- option.preferredVideoDecoder = [[NTESBundleSetting sharedConfig] perferredVideoDecoder];
- option.videoMaxEncodeBitrate = [[NTESBundleSetting sharedConfig] videoMaxEncodeKbps] * 1000;
- option.autoDeactivateAudioSession = [[NTESBundleSetting sharedConfig] autoDeactivateAudioSession];
- option.audioDenoise = [[NTESBundleSetting sharedConfig] audioDenoise];
- option.voiceDetect = [[NTESBundleSetting sharedConfig] voiceDetect];
- option.audioHowlingSuppress = [[NTESBundleSetting sharedConfig] audioHowlingSuppress];
- option.preferHDAudio = [[NTESBundleSetting sharedConfig] preferHDAudio];
- option.scene = [[NTESBundleSetting sharedConfig] scene];
- NIMNetCallVideoCaptureParam *param = [[NIMNetCallVideoCaptureParam alloc] init];
- [self fillVideoCaptureSetting:param];
- option.videoCaptureParam = param;
- }
- - (void)fillVideoCaptureSetting:(NIMNetCallVideoCaptureParam *)param {
- param.preferredVideoQuality = [[NTESBundleSetting sharedConfig] preferredVideoQuality];
- param.videoCrop = [[NTESBundleSetting sharedConfig] videochatVideoCrop];
- param.startWithBackCamera = [[NTESBundleSetting sharedConfig] startWithBackCamera];
- }
- #pragma mark - Ring
- //铃声 - 正在呼叫请稍后
- - (void)playConnnetRing {
- [self.player stop];
- NSURL *url = [[NSBundle mainBundle] URLForResource:@"video_connect_chat_tip_sender" withExtension:@"aac"];
- self.player = [[AVAudioPlayer alloc] initWithContentsOfURL:url error:nil];
- [self.player play];
- }
- //铃声 - 对方暂时无法接听
- - (void)playHangUpRing {
- [self.player stop];
- NSURL *url = [[NSBundle mainBundle] URLForResource:@"video_chat_tip_HangUp" withExtension:@"aac"];
- self.player = [[AVAudioPlayer alloc] initWithContentsOfURL:url error:nil];
- [self.player play];
- }
- //铃声 - 对方正在通话中
- - (void)playOnCallRing {
- [self.player stop];
- NSURL *url = [[NSBundle mainBundle] URLForResource:@"video_chat_tip_OnCall" withExtension:@"aac"];
- self.player = [[AVAudioPlayer alloc] initWithContentsOfURL:url error:nil];
- [self.player play];
- }
- //铃声 - 对方无人接听
- - (void)playTimeoutRing {
- [self.player stop];
- NSURL *url = [[NSBundle mainBundle] URLForResource:@"video_chat_tip_onTimer" withExtension:@"aac"];
- self.player = [[AVAudioPlayer alloc] initWithContentsOfURL:url error:nil];
- [self.player play];
- }
- //铃声 - 接收方铃声
- - (void)playReceiverRing {
- [self.player stop];
- NSURL *url = [[NSBundle mainBundle] URLForResource:@"video_chat_tip_receiver" withExtension:@"aac"];
- self.player = [[AVAudioPlayer alloc] initWithContentsOfURL:url error:nil];
- self.player.numberOfLoops = 20;
- [self.player play];
- }
- //铃声 - 拨打方铃声
- - (void)playSenderRing {
- [self.player stop];
- NSURL *url = [[NSBundle mainBundle] URLForResource:@"video_chat_tip_sender" withExtension:@"aac"];
- self.player = [[AVAudioPlayer alloc] initWithContentsOfURL:url error:nil];
- self.player.numberOfLoops = 20;
- [self.player play];
- }
- - (void)startChat {
- NSString *now = [Helper getCurrentTimes];
- NSString *str = [NSString stringWithFormat:@"%@order?action=doBegVChat&pk=%@&modelpk=%@&begdate=%@&hasanswer=0", imageURl, [Helper sharedAccount].accid, self.modelPk, now];
- NSLog(@"str========%@", str);
- [[AHHttpManager sharedManager] POST:[str stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding] parameters:nil success:^(id responseObject) {
- NSLog(@"%@", responseObject);
- if ([[responseObject objectForKey:@"msg"] isEqualToString:@"success"]) {
- } else {
- //[MBProgressHUD showTextHUD:@"超时" inView:self.view hideAfterDelay:1];
- }
- } failure:^(NSError *error) {
- NSLog(@"error = %@", error);
- //[MBProgressHUD showTextHUD:@"超时" inView:self.view hideAfterDelay:1];
- }];
- }
- @end
|