Files
ifish/Ifish/controllers/IfishTabControllers/消息/IfishIMFiles/Sessions/ViewController/VideoChat/NTESNetChatViewController.m
T
2017-08-15 16:59:01 +08:00

930 lines
32 KiB
Objective-C
Executable File

//
// 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 "Toast+UIView.h"
#import "NTESTimerHolder.h"
#import "NetCallChatInfo.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 40
//周期性检查剩余磁盘空间
#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
NTES_FORBID_INTERACTIVE_POP
- (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 = [[NetCallChatInfo 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{
[[NIMAVChatSDK sharedSDK].netCallManager removeDelegate:self];
}
- (void)viewDidLoad {
[super viewDidLoad];
__weak typeof(self) wself = self;
[self checkServiceEnable:^(BOOL result) {
if (result) {
[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];
[self setUpStatusBar:UIStatusBarStyleLightContent];
}
- (void)viewDidAppear:(BOOL)animated{
[super viewDidAppear:animated];
[UIApplication sharedApplication].idleTimerDisabled = YES;
}
- (void)viewWillDisappear:(BOOL)animated{
[super viewWillDisappear:animated];
[self.player stop];
[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) {
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.apnsSound = @"video_chat_tip_receiver.aac";
[self fillUserSetting:option];
__weak typeof(self) wself = self;
[[NIMAVChatSDK sharedSDK].netCallManager start:callees type:wself.callInfo.callType option:option completion:^(NSError *error, UInt64 callID) {
if (!error && wself) {
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{
if (error) {
[wself.navigationController.view makeToast:@"连接失败"
];
}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) {
[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:@"通话失败"
];
[wself hangup];
}
});
}else{
wself.chatRoom = nil;
[wself.navigationController.view makeToast:@"连接失败"
];
[wself dismiss:nil];
}
}];
//dismiss需要放在self后面,否在ios7下会有野指针
if (accept) {
[self waitForConnectiong];
}else{
[self dismiss:nil];
}
}
- (void)dismiss:(void (^)(void))completion{
//由于音视频聊天里头有音频和视频聊天界面的切换,直接用present的话页面过渡会不太自然,这里还是用push,然后做出present的效果
CATransition *transition = [CATransition animation];
transition.duration = 0.25;
transition.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionDefault];
transition.type = kCATransitionPush;
transition.subtype = kCATransitionFromBottom;
[self.navigationController.view.layer addAnimation:transition forKey:nil];
self.navigationController.navigationBarHidden = NO;
[self.navigationController popViewControllerAnimated:NO];
[self setUpStatusBar:UIStatusBarStyleDefault];
if (completion) {
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(transition.duration * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
completion();
});
}
}
- (void)onCalling{
//子类重写
}
- (void)waitForConnectiong{
//子类重写
}
-(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:@"开始录制失败"
];
}
else
{
[self.view makeToast:toastText
];
}
}
}
- (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:@"结束录制失败"
];
}
else
{
[self.view makeToast:toastText
];
}
}
}
-(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:@"无人接听"];
[wself dismiss:nil];
}
});
}
break;
}
case NIMNetCallControlTypeBusyLine: {
[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 dismiss:nil];
});
break;
}
case NIMNetCallControlTypeStartRecord:
[self.view makeToast:@"对方开始了录制"
];
break;
case NIMNetCallControlTypeStopRecord:
[self.view makeToast:@"对方结束了录制"
];
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:@"对方拒绝接听"
];
[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 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:@"已在其他端处理"
];
[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
{
if (self.callInfo.callID == callID) {
[self.view makeToast:[NSString stringWithFormat:@"录制发生错误: %zd", error.code]
];
if ([userId isEqualToString:[[NIMSDK sharedSDK].loginManager currentAccount]]) {
self.callInfo.localRecording = NO;
}
if ([userId isEqualToString:self.peerUid]) {
self.callInfo.otherSideRecording = NO;
}
}
if (error.code == NIMLocalErrorCodeRecordWillStopForLackSpace) {
_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:@"接听超时"];
[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);
}
}];
}
});
}];
}
}
- (void)setUpStatusBar:(UIStatusBarStyle)style{
[[UIApplication sharedApplication] setStatusBarStyle:style
animated:NO];
}
- (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:@"保存失败,没有相册权限"
];
});
}
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
];
}
_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.preferredVideoQuality = [[NTESBundleSetting sharedConfig] preferredVideoQuality];
option.disableVideoCropping = [[NTESBundleSetting sharedConfig] videochatDisableAutoCropping];
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.startWithBackCamera = [[NTESBundleSetting sharedConfig] startWithBackCamera];
option.autoDeactivateAudioSession = [[NTESBundleSetting sharedConfig] autoDeactivateAudioSession];
option.audioDenoise = [[NTESBundleSetting sharedConfig] audioDenoise];
option.voiceDetect = [[NTESBundleSetting sharedConfig] voiceDetect];
option.preferHDAudio = [[NTESBundleSetting sharedConfig] preferHDAudio];
}
#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];
}
@end