ifish/Ifish/controllers/IfishTabControllers/消息/IfishIMFiles/Sessions/ViewController/VideoChat/NTESNetChatViewController.m

930 lines
32 KiB
Objective-C
Executable File
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//
// 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