iOS环信视频聊天

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了iOS环信视频聊天相关的知识,希望对你有一定的参考价值。

这是我自己利用环信写的一个单纯的视频聊天功能demo

首先需要去环信官网申请一个appkey,并将sdk集成到项目中

然后加入类库

技术分享

APPDelegate.m

 

//
//  AppDelegate.m
//  VideoChat
//
//  Created by 小灰灰的pro on 16/8/31.
//  Copyright © 2016年 小灰灰. All rights reserved.
//

#import "AppDelegate.h"
#import "EMSDK.h"

@interface AppDelegate ()

@end

@implementation AppDelegate


- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    // Override point for customization after application launch.
    //AppKey:注册的AppKey,详细见下面注释。
    //apnsCertName:推送证书名(不需要加后缀),详细见下面注释。
    EMOptions *options = [EMOptions optionsWithAppkey:@"appkey"];
    options.apnsCertName = nil;
    [[EMClient sharedClient] initializeSDKWithOptions:options];
    
       return YES;
}

- (void)applicationWillResignActive:(UIApplication *)application {
    // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
    // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
}

- (void)applicationDidEnterBackground:(UIApplication *)application {
    // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
    // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
    [[EMClient sharedClient] applicationDidEnterBackground:application];
}

- (void)applicationWillEnterForeground:(UIApplication *)application {
    // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background.
    [[EMClient sharedClient] applicationWillEnterForeground:application];
}

 

 

 ViewController.h

 

//
//  ViewController.h
//  VideoChat
//
//  Created by 小灰灰的pro on 16/8/31.
//  Copyright © 2016年 小灰灰. All rights reserved.
//

#import <UIKit/UIKit.h>
#import "EMCallManagerDelegate.h"
#import "CallViewController.h"
@interface ViewController : UIViewController<EMCallManagerDelegate>
//@property (nonatomic, weak) ViewController *mainVC;

@property (strong, nonatomic) EMCallSession *callSession;
@property (strong, nonatomic) CallViewController *callController;

- (void)makeCallWithUsername:(NSString *)aUsername
                     isVideo:(BOOL)aIsVideo;

- (void)hangupCallWithReason:(EMCallEndReason)aReason answerCall:(EMCallSession *)session;

- (void)answerCall:(EMCallSession *)session;


@end

 

 ViewController.m

//
//  ViewController.m
//  VideoChat
//
//  Created by 小灰灰的pro on 16/8/31.
//  Copyright © 2016年 小灰灰. All rights reserved.
//

#import "ViewController.h"
//#import "ChatDemoHelper.h"
#import "EMClient+Call.h"
#define KNOTIFICATION_CALL @"callOutWithChatter"
@interface ViewController ()<EMCallManagerDelegate>
{
    NSTimer *_callTimer;
}


@end

//static ViewController *helper = nil;

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
//    EMError *error = [[EMClient sharedClient] registerWithUsername:@"111" password:@"222"];
//    if (error==nil) {
//        NSLog(@"注册成功");
//    }
    
    //自动登录方法
//假如用户名为111,密码为222
EMError *error = [[EMClient sharedClient] loginWithUsername:@"111" password:@"222"]; if (!error) { [[EMClient sharedClient].options setIsAutoLogin:YES]; } //设置代理对象,接打视频的代理方法 [[EMClient sharedClient].callManager addDelegate:self delegateQueue:nil]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(makeCall:) name:KNOTIFICATION_CALL object:nil]; //拨视频的按钮 UIButton *chatButton = [[UIButton alloc] initWithFrame:CGRectMake(100, 100, 200, 50)]; chatButton.backgroundColor = [UIColor redColor]; [chatButton addTarget:self action:@selector(buttonAction) forControlEvents:UIControlEventTouchUpInside]; [self.view addSubview:chatButton]; } - (void)buttonAction{
//这是要打给qqq调用的方法 [self makeCallWithUsername:
@"qqq" isVideo:YES]; } //这是调用视频接收方的代理方法 #pragma mark - EMCallManagerDelegate //视频接收到的方法 - (void)didReceiveCallIncoming:(EMCallSession *)aSession { if(_callSession && _callSession.status != EMCallSessionStatusDisconnected){ [[EMClient sharedClient].callManager endCall:aSession.sessionId reason:EMCallEndReasonBusy]; } if ([[UIApplication sharedApplication] applicationState] != UIApplicationStateActive) { [[EMClient sharedClient].callManager endCall:aSession.sessionId reason:EMCallEndReasonFailed]; } _callSession = aSession; if(_callSession){ [self _startCallTimer]; _callController = [[CallViewController alloc] initWithSession:_callSession isCaller:NO status:NSLocalizedString(@"call.finished", "Establish call finished")]; _callController.modalPresentationStyle = UIModalPresentationOverFullScreen; _callController.cSession = aSession; //跳转到视频的页面 [self presentViewController:_callController animated:NO completion:nil]; } } // - (void)didReceiveCallConnected:(EMCallSession *)aSession { if ([aSession.sessionId isEqualToString:_callSession.sessionId]) { _callController.statusLabel.text = NSLocalizedString(@"call.finished", "Establish call finished"); AVAudiosession *audioSession = [AVAudioSession sharedInstance]; [audioSession setCategory:AVAudioSessionCategoryPlayAndRecord error:nil]; [audioSession setActive:YES error:nil]; } } - (void)didReceiveCallAccepted:(EMCallSession *)aSession { if ([[UIApplication sharedApplication] applicationState] != UIApplicationStateActive) { [[EMClient sharedClient].callManager endCall:aSession.sessionId reason:EMCallEndReasonFailed]; } if ([aSession.sessionId isEqualToString:_callSession.sessionId]) { [self _stopCallTimer]; NSString *connectStr = aSession.connectType == EMCallConnectTypeRelay ? @"Relay" : @"Direct"; _callController.statusLabel.text = [NSString stringWithFormat:@"%@ %@",NSLocalizedString(@"call.speak", @"Can speak..."), connectStr]; _callController.timeLabel.hidden = NO; [_callController startTimer]; [_callController startShowInfo]; _callController.cancelButton.hidden = NO; _callController.rejectButton.hidden = YES; _callController.answerButton.hidden = YES; } } - (void)didReceiveCallTerminated:(EMCallSession *)aSession reason:(EMCallEndReason)aReason error:(EMError *)aError { if ([aSession.sessionId isEqualToString:_callSession.sessionId]) { [self _stopCallTimer]; _callSession = nil; [_callController close]; _callController = nil; if (aReason != EMCallEndReasonHangup) { NSString *reasonStr = @""; switch (aReason) { case EMCallEndReasonNoResponse: { reasonStr = NSLocalizedString(@"call.noResponse", @"NO response"); } break; case EMCallEndReasonDecline: { reasonStr = NSLocalizedString(@"call.rejected", @"Reject the call"); } break; case EMCallEndReasonBusy: { reasonStr = NSLocalizedString(@"call.in", @"In the call..."); } break; case EMCallEndReasonFailed: { reasonStr = NSLocalizedString(@"call.connectFailed", @"Connect failed"); } break; default: break; } if (aError) { UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"Error" message:aError.errorDescription delegate:nil cancelButtonTitle:NSLocalizedString(@"ok", @"OK") otherButtonTitles:nil, nil]; [alertView show]; } else{ UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:nil message:reasonStr delegate:nil cancelButtonTitle:NSLocalizedString(@"ok", @"OK") otherButtonTitles:nil, nil]; [alertView show]; } } } } - (void)didReceiveCallNetworkChanged:(EMCallSession *)aSession status:(EMCallNetworkStatus)aStatus { if ([aSession.sessionId isEqualToString:_callSession.sessionId]) { // [_callController setNetwork:aStatus]; } } //调用拨打方的代理方法 #pragma mark - public - (void)makeCall:(NSNotification*)notify { if (notify.object) { [self makeCallWithUsername:[notify.object valueForKey:@"chatter"] isVideo:[[notify.object objectForKey:@"type"] boolValue]]; } } - (void)_startCallTimer { _callTimer = [NSTimer scheduledTimerWithTimeInterval:50 target:self selector:@selector(_cancelCall) userInfo:nil repeats:NO]; } - (void)_stopCallTimer { if (_callTimer == nil) { return; } [_callTimer invalidate]; _callTimer = nil; } - (void)_cancelCall { [self hangupCallWithReason:EMCallEndReasonNoResponse answerCall:nil]; UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:nil message:NSLocalizedString(@"call.autoHangup", @"No response and Hang up") delegate:self cancelButtonTitle:NSLocalizedString(@"ok", @"OK") otherButtonTitles:nil, nil]; [alertView show]; } - (void)makeCallWithUsername:(NSString *)aUsername isVideo:(BOOL)aIsVideo { if ([aUsername length] == 0) { return; } __weak typeof(self) weakSelf = self; void (^completionBlock)(EMCallSession *, EMError *) = ^(EMCallSession *aCallSession, EMError *aError){ ViewController *strongSelf = weakSelf; if (strongSelf) { if (!aError && aCallSession) { strongSelf.callSession = aCallSession; [strongSelf _startCallTimer]; strongSelf.callController = [[CallViewController alloc] initWithSession:self.callSession isCaller:YES status:NSLocalizedString(@"call.connecting", @"Connecting...")]; self.callController.cSession = self.callSession; [self presentViewController:self.callController animated:NO completion:nil]; } else { UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:nil message:NSLocalizedString(@"call.initFailed", @"Failed to establish the call") delegate:nil cancelButtonTitle:NSLocalizedString(@"ok", @"OK") otherButtonTitles:nil, nil]; [alertView show]; } } else { [[EMClient sharedClient].callManager endCall:aCallSession.sessionId reason:EMCallEndReasonNoResponse]; } }; if (aIsVideo) { [[EMClient sharedClient].callManager startVideoCall:aUsername completion:^(EMCallSession *aCallSession, EMError *aError) { completionBlock(aCallSession, aError); }]; } else { [[EMClient sharedClient].callManager startVoiceCall:aUsername completion:^(EMCallSession *aCallSession, EMError *aError) { completionBlock(aCallSession, aError); }]; } } - (void)hangupCallWithReason:(EMCallEndReason)aReason answerCall:(EMCallSession *)session { [self _stopCallTimer]; if (session) { _callSession = session; } else { } if (_callSession) { [[EMClient sharedClient].callManager endCall:_callSession.sessionId reason:aReason]; } _callSession = nil; [_callController close]; _callController = nil; } - (void)answerCall:(EMCallSession *)session { _callSession = session; if (_callSession) { dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ EMError *error = [[EMClient sharedClient].callManager answerIncomingCall:self.callSession.sessionId]; if (error) { dispatch_async(dispatch_get_main_queue(), ^{ if (error.code == EMErrorNetworkUnavailable) { UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:nil message:NSLocalizedString(@"network.disconnection", @"Network disconnection") delegate:nil cancelButtonTitle:NSLocalizedString(@"ok", @"OK") otherButtonTitles:nil, nil]; [alertView show]; } else{ [self hangupCallWithReason:EMCallEndReasonFailed answerCall:nil]; } }); } }); } } @end

CallViewController.h

 

 1 /************************************************************
 2  *  * Hyphenate CONFIDENTIAL
 3  * __________________
 4  * Copyright (C) 2016 Hyphenate Inc. All rights reserved.
 5  *
 6  * NOTICE: All information contained herein is, and remains
 7  * the property of Hyphenate Inc.
 8  * Dissemination of this information or reproduction of this material
 9  * is strictly forbidden unless prior written permission is obtained
10  * from Hyphenate Inc.
11  */
12 
13 #import <AVFoundation/AVFoundation.h>
14 #import <UIKit/UIKit.h>
15 #import "EMClient+Call.h"
16 #define kLocalCallBitrate @"EaseMobLocalCallBitrate"
17 
18 @class EMCallSession;
19 @interface CallViewController : UIViewController
20 {
21     NSTimer *_timeTimer;
22     AVAudioPlayer *_ringPlayer;
23     
24     UIView *_topView;
25     UILabel *_statusLabel;
26     UILabel *_timeLabel;
27     UILabel *_nameLabel;
28     UIImageView *_headerImageView;
29     
30     //操作按钮显示
31     UIView *_actionView;
32     UIButton *_silenceButton;
33     UILabel *_silenceLabel;
34     UIButton *_speakerOutButton;
35     UILabel *_speakerOutLabel;
36     UIButton *_rejectButton;
37     UIButton *_answerButton;
38     UIButton *_cancelButton;
39     
40     UIButton *_recordButton;
41     UIButton *_videoButton;
42     UIButton *_voiceButton;
43     UIButton *_switchCameraButton;
44     
45 }
46 
47 @property (strong, nonatomic) UILabel *statusLabel;
48 
49 @property (strong, nonatomic) UILabel *timeLabel;
50 
51 @property (strong, nonatomic) UIButton *rejectButton;
52 
53 @property (strong, nonatomic) UIButton *answerButton;
54 
55 @property (strong, nonatomic) UIButton *cancelButton;
56 
57 @property (strong, nonatomic) EMCallSession *cSession;
58 
59 - (instancetype)initWithSession:(EMCallSession *)session
60                        isCaller:(BOOL)isCaller
61                          status:(NSString *)statusString;
62 
63 + (BOOL)canVideo;
64 
65 + (void)saveBitrate:(NSString*)value;
66 
67 - (void)startTimer;
68 
69 - (void)startShowInfo;
70 
71 - (void)close;
72 
73 //- (void)setNetwork:(EMCallNetworkStatus)status;
74 
75 
76 @end

CallViewController.m

************************************************************
 *  * Hyphenate CONFIDENTIAL
 * __________________
 * Copyright (C) 2016 Hyphenate Inc. All rights reserved.
 *
 * NOTICE: All information contained herein is, and remains
 * the property of Hyphenate Inc.
 * Dissemination of this information or reproduction of this material
 * is strictly forbidden unless prior written permission is obtained
 * from Hyphenate Inc.
 */

#import <CoreTelephony/CTCallCenter.h>
#import <CoreTelephony/CTCall.h>
#import "CallViewController.h"

#import "ViewController.h"
#define KNOTIFICATION_CALL @"callOutWithChatter"
@interface CallViewController ()
{
    __weak EMCallSession *_callSession;
    BOOL _isCaller;
    NSString *_status;
    int _timeLength;
    
    NSString * _audioCategory;
    
    //视频属性显示区域
    UIView *_propertyView;
    UILabel *_sizeLabel;
    UILabel *_timedelayLabel;
    UILabel *_framerateLabel;
    UILabel *_lostcntLabel;
    UILabel *_remoteBitrateLabel;
    UILabel *_localBitrateLabel;
    NSTimer *_propertyTimer;
    //弱网检测
    UILabel *_networkLabel;
}

@property (strong, nonatomic) UITapGestureRecognizer *tapRecognizer;

@end

@implementation CallViewController

- (instancetype)initWithSession:(EMCallSession *)session
                       isCaller:(BOOL)isCaller
                         status:(NSString *)statusString
{
    self = [super init];
    if (self) {
        _callSession = session;
        _isCaller = isCaller;
        _timeLabel.text = @"";
        _timeLength = 0;
        _status = statusString;
        
        NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
        if ([ud valueForKey:kLocalCallBitrate] && _callSession.type == EMCallTypeVideo) {
            [session setVideoBitrate:[[ud valueForKey:kLocalCallBitrate] intValue]];
        }
    }
    
    return self;
}

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    
    [self.view addGestureRecognizer:self.tapRecognizer];
    
    [self _setupSubviews];
    
    _nameLabel.text = _callSession.remoteUsername;
    _statusLabel.text = _status;
    if (_isCaller) {
        self.rejectButton.hidden = YES;
        self.answerButton.hidden = YES;
        self.cancelButton.hidden = NO;
    }
    else{
        self.cancelButton.hidden = YES;
        self.rejectButton.hidden = NO;
        self.answerButton.hidden = NO;
    }
    
    if (_callSession.type == EMCallTypeVideo) {
        [self _initializeVideoView];
        
        [self.view bringSubviewToFront:_topView];
        [self.view bringSubviewToFront:_actionView];
    }
}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

#pragma mark - getter

- (BOOL)isShowCallInfo
{
    id object = [[NSUserDefaults standardUserDefaults] objectForKey:@"showCallInfo"];
    return [object boolValue];
}

#pragma makr - property

- (UITapGestureRecognizer *)tapRecognizer
{
    if (_tapRecognizer == nil) {
        _tapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(viewTapAction:)];
    }
    
    return _tapRecognizer;
}

#pragma mark - subviews

- (void)_setupSubviews
{
    if ([self respondsToSelector:@selector(setEdgesForExtendedLayout:)])
    {
        [self setEdgesForExtendedLayout:UIRectEdgeNone];
    }
    self.navigationController.navigationBarHidden = YES;
    self.view.backgroundColor = [UIColor whiteColor];
    
    UIImageView *bgImageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height)];
    bgImageView.contentMode = UIViewContentModeScaleToFill;
    bgImageView.image = [UIImage imageNamed:@"[email protected]"];
    [self.view addSubview:bgImageView];
    
    _topView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, 150)];
    _topView.backgroundColor = [UIColor clearColor];
    [self.view addSubview:_topView];
    
    _statusLabel = [[UILabel alloc] initWithFrame:CGRectMake(10, 20, _topView.frame.size.width - 20, 20)];
    _statusLabel.font = [UIFont systemFontOfSize:15.0];
    _statusLabel.backgroundColor = [UIColor clearColor];
    _statusLabel.textColor = [UIColor whiteColor];
    _statusLabel.textAlignment = NSTextAlignmentCenter;
    [_topView addSubview:self.statusLabel];
    
    _timeLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, CGRectGetMaxY(_statusLabel.frame), _topView.frame.size.width, 15)];
    _timeLabel.font = [UIFont systemFontOfSize:12.0];
    _timeLabel.backgroundColor = [UIColor clearColor];
    _timeLabel.textColor = [UIColor whiteColor];
    _timeLabel.textAlignment = NSTextAlignmentCenter;
    [_topView addSubview:_timeLabel];
    
    _headerImageView = [[UIImageView alloc] initWithFrame:CGRectMake((_topView.frame.size.width - 50) / 2, CGRectGetMaxY(_statusLabel.frame) + 20, 50, 50)];
    _headerImageView.image = [UIImage imageNamed:@"user"];
    [_topView addSubview:_headerImageView];
    
    _nameLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, CGRectGetMaxY(_headerImageView.frame) + 5, _topView.frame.size.width, 20)];
    _nameLabel.font = [UIFont systemFontOfSize:14.0];
    _nameLabel.backgroundColor = [UIColor clearColor];
    _nameLabel.textColor = [UIColor whiteColor];
    _nameLabel.textAlignment = NSTextAlignmentCenter;
    _nameLabel.text = _callSession.remoteUsername;
    [_topView addSubview:_nameLabel];
    
    _networkLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, CGRectGetMaxY(_nameLabel.frame) + 5, _topView.frame.size.width, 20)];
    _networkLabel.font = [UIFont systemFontOfSize:14.0];
    _networkLabel.backgroundColor = [UIColor clearColor];
    _networkLabel.textColor = [UIColor whiteColor];
    _networkLabel.textAlignment = NSTextAlignmentCenter;
    _networkLabel.hidden = YES;
    [_topView addSubview:_networkLabel];
    
    if (_callSession.type == EMCallTypeVideo) {
        _switchCameraButton = [[UIButton alloc] initWithFrame:CGRectMake(20, CGRectGetMaxY(_statusLabel.frame) + 20, 60, 30)];
        [_switchCameraButton setBackgroundColor:[UIColor grayColor]];
        [_switchCameraButton setTitle:NSLocalizedString(@"旋转", @"Switch Camera") forState:UIControlStateNormal];
        [_switchCameraButton.titleLabel setFont:[UIFont systemFontOfSize:10]];
        [_switchCameraButton addTarget:self action:@selector(switchCameraAction) forControlEvents:UIControlEventTouchUpInside];
        _switchCameraButton.userInteractionEnabled = YES;
        [_topView addSubview:_switchCameraButton];
    }
    
    _actionView = [[UIView alloc] initWithFrame:CGRectMake(0, self.view.frame.size.height - 260, self.view.frame.size.width, 260)];
    _actionView.backgroundColor = [UIColor clearColor];
    [self.view addSubview:_actionView];
    
    CGFloat tmpWidth = _actionView.frame.size.width / 2;
    _silenceButton = [[UIButton alloc] initWithFrame:CGRectMake((tmpWidth - 40) / 2, 80, 40, 40)];
//    [_silenceButton setImage:[UIImage imageNamed:@"call_silence"] forState:UIControlStateNormal];
    [_silenceButton setTitle:@"静音" forState:UIControlStateNormal];
    [_silenceButton setImage:[UIImage imageNamed:@"call_silence_h"] forState:UIControlStateSelected];
    [_silenceButton setTitle:@"声音" forState:UIControlStateSelected];
    [_silenceButton addTarget:self action:@selector(silenceAction) forControlEvents:UIControlEventTouchUpInside];
        [_actionView addSubview:_silenceButton];
    
    _silenceLabel = [[UILabel alloc] initWithFrame:CGRectMake(30, CGRectGetMaxY(_silenceButton.frame) + 5, tmpWidth - 60, 20)];
    _silenceLabel.backgroundColor = [UIColor clearColor];
    _silenceLabel.textColor = [UIColor whiteColor];
    _silenceLabel.font = [UIFont systemFontOfSize:13.0];
    _silenceLabel.textAlignment = NSTextAlignmentCenter;
    _silenceLabel.text = NSLocalizedString(@"call.silence", @"Silence");
        [_actionView addSubview:_silenceLabel];
    
    _speakerOutButton = [[UIButton alloc] initWithFrame:CGRectMake(tmpWidth + (tmpWidth - 40) / 2, _silenceButton.frame.origin.y, 40, 40)];
//    [_speakerOutButton setImage:[UIImage imageNamed:@"call_out"] forState:UIControlStateNormal];
    [_speakerOutButton setTitle:@"免提" forState:UIControlStateNormal];
//    [_speakerOutButton setImage:[UIImage imageNamed:@"call_out_h"] forState:UIControlStateSelected];
    [_speakerOutButton setTitle:@"听筒" forState:UIControlStateSelected];
    [_speakerOutButton addTarget:self action:@selector(speakerOutAction) forControlEvents:UIControlEventTouchUpInside];
        [_actionView addSubview:_speakerOutButton];
    
    _speakerOutLabel = [[UILabel alloc] initWithFrame:CGRectMake(tmpWidth + 30, CGRectGetMaxY(_speakerOutButton.frame) + 5, tmpWidth - 60, 20)];
    _speakerOutLabel.backgroundColor = [UIColor clearColor];
    _speakerOutLabel.textColor = [UIColor whiteColor];
    _speakerOutLabel.font = [UIFont systemFontOfSize:13.0];
    _speakerOutLabel.textAlignment = NSTextAlignmentCenter;
    _speakerOutLabel.text = NSLocalizedString(@"call.speaker", @"Speaker");
        [_actionView addSubview:_speakerOutLabel];
    
    _rejectButton = [[UIButton alloc] initWithFrame:CGRectMake((tmpWidth - 100) / 2, CGRectGetMaxY(_speakerOutLabel.frame) + 30, 100, 40)];
    [_rejectButton setTitle:NSLocalizedString(@"call.reject", @"Reject") forState:UIControlStateNormal];
    [_rejectButton setBackgroundColor:[UIColor colorWithRed:191 / 255.0 green:48 / 255.0 blue:49 / 255.0 alpha:1.0]];
    [_rejectButton addTarget:self action:@selector(rejectAction) forControlEvents:UIControlEventTouchUpInside];
    [_actionView addSubview:_rejectButton];
    
    _answerButton = [[UIButton alloc] initWithFrame:CGRectMake(tmpWidth + (tmpWidth - 100) / 2, _rejectButton.frame.origin.y, 100, 40)];
    [_answerButton setTitle:NSLocalizedString(@"call.answer", @"Answer") forState:UIControlStateNormal];
    [_answerButton setBackgroundColor:[UIColor colorWithRed:191 / 255.0 green:48 / 255.0 blue:49 / 255.0 alpha:1.0]];;
    [_answerButton addTarget:self action:@selector(answerAction) forControlEvents:UIControlEventTouchUpInside];

    [_actionView addSubview:_answerButton];
    
    _cancelButton = [[UIButton alloc] initWithFrame:CGRectMake((self.view.frame.size.width - 200) / 2, _rejectButton.frame.origin.y, 200, 40)];
    [_cancelButton setTitle:NSLocalizedString(@"call.hangup", @"Hangup") forState:UIControlStateNormal];
    [_cancelButton setBackgroundColor:[UIColor colorWithRed:191 / 255.0 green:48 / 255.0 blue:49 / 255.0 alpha:1.0]];;
    [_cancelButton addTarget:self action:@selector(hangupAction) forControlEvents:UIControlEventTouchUpInside];
    [_actionView addSubview:_cancelButton];
    
    if (_callSession.type == EMCallTypeVideo) {
        CGFloat tmpWidth = _actionView.frame.size.width / 3;
        _recordButton = [[UIButton alloc] initWithFrame:CGRectMake((tmpWidth-40)/2, 20, 40, 40)];
        _recordButton.layer.cornerRadius = 20.f;
        [_recordButton setTitle:@"录制" forState:UIControlStateNormal];
        [_recordButton setTitle:@"停止播放" forState:UIControlStateSelected];
        [_recordButton.titleLabel setFont:[UIFont systemFontOfSize:10]];
        [_recordButton setBackgroundColor:[UIColor grayColor]];
        [_recordButton addTarget:self action:@selector(recordAction) forControlEvents:UIControlEventTouchUpInside];
//        [_actionView addSubview:_recordButton];
        _videoButton = [[UIButton alloc] initWithFrame:CGRectMake(tmpWidth + (tmpWidth - 40) / 2, 20, 40, 40)];
        _videoButton.layer.cornerRadius = 20.f;
        [_videoButton setTitle:@"视频开启" forState:UIControlStateNormal];
        [_videoButton setTitle:@"视频中断" forState:UIControlStateSelected];
        [_videoButton.titleLabel setFont:[UIFont systemFontOfSize:10]];
        [_videoButton setBackgroundColor:[UIColor grayColor]];
        [_videoButton addTarget:self action:@selector(videoPauseAction) forControlEvents:UIControlEventTouchUpInside];
//        [_actionView addSubview:_videoButton];
        _voiceButton = [[UIButton alloc] initWithFrame:CGRectMake(tmpWidth * 2 + (tmpWidth - 40) / 2, 20, 40, 40)];
        _voiceButton.layer.cornerRadius = 20.f;
        [_voiceButton setTitle:@"音视开启" forState:UIControlStateNormal];
        [_voiceButton setTitle:@"音视中断" forState:UIControlStateSelected];
        [_voiceButton.titleLabel setFont:[UIFont systemFontOfSize:10]];
        [_voiceButton setBackgroundColor:[UIColor grayColor]];
        [_voiceButton addTarget:self action:@selector(voicePauseAction) forControlEvents:UIControlEventTouchUpInside];
//        [_actionView addSubview:_voiceButton];
    }
}

- (void)_initializeVideoView
{
    //1.对方窗口
    _callSession.remoteVideoView = [[EMCallRemoteView alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height)];
    [self.view addSubview:_callSession.remoteVideoView];
    
    //2.自己窗口
    CGFloat width = 80;
    CGFloat height = self.view.frame.size.height / self.view.frame.size.width * width;
    _callSession.localVideoView = [[EMCallLocalView alloc] initWithFrame:CGRectMake(self.view.frame.size.width - 90, CGRectGetMaxY(_statusLabel.frame), width, height)];
    [self.view addSubview:_callSession.localVideoView];
    
    //3、属性显示层
    _propertyView = [[UIView alloc] initWithFrame:CGRectMake(10, CGRectGetMinY(_actionView.frame) - 90, self.view.frame.size.width - 20, 90)];
    _propertyView.backgroundColor = [UIColor clearColor];
    _propertyView.hidden = ![self isShowCallInfo];
    [self.view addSubview:_propertyView];
    
    width = (CGRectGetWidth(_propertyView.frame) - 20) / 2;
    height = CGRectGetHeight(_propertyView.frame) / 3;
    _sizeLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, width, height)];
    _sizeLabel.backgroundColor = [UIColor clearColor];
    _sizeLabel.textColor = [UIColor redColor];
    [_propertyView addSubview:_sizeLabel];
    
    _timedelayLabel = [[UILabel alloc] initWithFrame:CGRectMake(width, 0, width, height)];
    _timedelayLabel.backgroundColor = [UIColor clearColor];
    _timedelayLabel.textColor = [UIColor redColor];
    [_propertyView addSubview:_timedelayLabel];
    
    _framerateLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, height, width, height)];
    _framerateLabel.backgroundColor = [UIColor clearColor];
    _framerateLabel.textColor = [UIColor redColor];
    [_propertyView addSubview:_framerateLabel];
    
    _lostcntLabel = [[UILabel alloc] initWithFrame:CGRectMake(width, height, width, height)];
    _lostcntLabel.backgroundColor = [UIColor clearColor];
    _lostcntLabel.textColor = [UIColor redColor];
    [_propertyView addSubview:_lostcntLabel];
    
    _localBitrateLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, height * 2, width, height)];
    _localBitrateLabel.backgroundColor = [UIColor clearColor];
    _localBitrateLabel.textColor = [UIColor redColor];
    [_propertyView addSubview:_localBitrateLabel];
    
    _remoteBitrateLabel = [[UILabel alloc] initWithFrame:CGRectMake(width, height * 2, width, height)];
    _remoteBitrateLabel.backgroundColor = [UIColor clearColor];
    _remoteBitrateLabel.textColor = [UIColor redColor];
    [_propertyView addSubview:_remoteBitrateLabel];
}

#pragma mark - private

- (void)_reloadPropertyData
{
    if (_callSession) {
        _sizeLabel.text = [NSString stringWithFormat:@"%@%i/%i", NSLocalizedString(@"call.videoSize", @"Width/Height: "), [_callSession getVideoWidth], [_callSession getVideoHeight]];
        _timedelayLabel.text = [NSString stringWithFormat:@"%@%i", NSLocalizedString(@"call.videoTimedelay", @"Timedelay: "), [_callSession getVideoLatency]];
        _framerateLabel.text = [NSString stringWithFormat:@"%@%i", NSLocalizedString(@"call.videoFramerate", @"Framerate: "), [_callSession getVideoFrameRate]];
        _lostcntLabel.text = [NSString stringWithFormat:@"%@%i", NSLocalizedString(@"call.videoLostcnt", @"Lostcnt: "), [_callSession getVideoLostRateInPercent]];
        _localBitrateLabel.text = [NSString stringWithFormat:@"%@%i", NSLocalizedString(@"call.videoLocalBitrate", @"Local Bitrate: "), [_callSession getVideoLocalBitrate]];
        _remoteBitrateLabel.text = [NSString stringWithFormat:@"%@%i", NSLocalizedString(@"call.videoRemoteBitrate", @"Remote Bitrate: "), [_callSession getVideoRemoteBitrate]];
    }
}

- (void)_beginRing
{
    [_ringPlayer stop];
    
    NSString *musicPath = [[NSBundle mainBundle] pathForResource:@"callRing" ofType:@"mp3"];
    NSURL *url = [[NSURL alloc] initFileURLWithPath:musicPath];
    
    _ringPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:url error:nil];
    [_ringPlayer setVolume:1];
    _ringPlayer.numberOfLoops = -1; //设置音乐播放次数  -1为一直循环
    if([_ringPlayer prepareToPlay])
    {
        [_ringPlayer play]; //播放
    }
}

- (void)_stopRing
{
    [_ringPlayer stop];
}

- (void)timeTimerAction:(id)sender
{
    _timeLength += 1;
    int hour = _timeLength / 3600;
    int m = (_timeLength - hour * 3600) / 60;
    int s = _timeLength - hour * 3600 - m * 60;
    
    if (hour > 0) {
        _timeLabel.text = [NSString stringWithFormat:@"%i:%i:%i", hour, m, s];
    }
    else if(m > 0){
        _timeLabel.text = [NSString stringWithFormat:@"%i:%i", m, s];
    }
    else{
        _timeLabel.text = [NSString stringWithFormat:@"00:%i", s];
    }
}

#pragma mark - UITapGestureRecognizer

- (void)viewTapAction:(UITapGestureRecognizer *)tap
{
    _topView.hidden = !_topView.hidden;
    _actionView.hidden = !_actionView.hidden;
}

#pragma mark - action

- (void)switchCameraAction
{
    [_callSession switchCameraPosition:_switchCameraButton.selected];
    _switchCameraButton.selected = !_switchCameraButton.selected;
}

- (void)recordAction
{
    _recordButton.selected = !_recordButton.selected;
    if (_recordButton.selected) {
        NSString *recordPath = NSHomeDirectory();
        recordPath = [NSString stringWithFormat:@"%@/Library/appdata/chatbuffer",recordPath];
        NSFileManager *fm = [NSFileManager defaultManager];
        if(![fm fileExistsAtPath:recordPath]){
            [fm createDirectoryAtPath:recordPath
          withIntermediateDirectories:YES
                           attributes:nil
                                error:nil];
        }
        [_callSession startVideoRecordingToFilePath:recordPath error:nil];
    } else {
        NSString *tempPath = [_callSession stopVideoRecording:nil];
        if (tempPath.length > 0) {
//            NSURL *videoURL = [NSURL fileURLWithPath:tempPath];
//            MPMoviePlayerViewController *moviePlayerController = [[MPMoviePlayerViewController alloc] initWithContentURL:videoURL];
//            [moviePlayerController.moviePlayer prepareToPlay];
//            moviePlayerController.moviePlayer.movieSourceType = MPMovieSourceTypeFile;
//            [self presentMoviePlayerViewControllerAnimated:moviePlayerController];
        }
    }
}

- (void)videoPauseAction
{
    _videoButton.selected = !_videoButton.selected;
    if (_videoButton.selected) {
        [[EMClient sharedClient].callManager pauseVideoWithSession:_callSession.sessionId error:nil];
    } else {
        [[EMClient sharedClient].callManager resumeVideoWithSession:_callSession.sessionId error:nil];
    }
}

- (void)voicePauseAction
{
    _voiceButton.selected = !_voiceButton.selected;
    if (_voiceButton.selected) {
        [[EMClient sharedClient].callManager pauseVoiceWithSession:_callSession.sessionId error:nil];
    } else {
        [[EMClient sharedClient].callManager resumeVoiceWithSession:_callSession.sessionId error:nil];
    }
}

- (void)silenceAction
{
    _silenceButton.selected = !_silenceButton.selected;
    if (_silenceButton.selected) {
        [[EMClient sharedClient].callManager pauseVoiceWithSession:_callSession.sessionId error:nil];
    } else {
        [[EMClient sharedClient].callManager resumeVoiceWithSession:_callSession.sessionId error:nil];
    }
}

- (void)speakerOutAction
{
    AVAudioSession *audioSession = [AVAudioSession sharedInstance];
    if (_speakerOutButton.selected) {
        [audioSession overrideOutputAudioPort:AVAudioSessionPortOverrideNone error:nil];
    }else {
        [audioSession overrideOutputAudioPort:AVAudioSessionPortOverrideSpeaker error:nil];
    }
    [audioSession setActive:YES error:nil];
    _speakerOutButton.selected = !_speakerOutButton.selected;
}

- (void)answerAction
{
    [self _stopRing];
    AVAudioSession *audioSession = [AVAudioSession sharedInstance];
    _audioCategory = audioSession.category;
    if(![_audioCategory isEqualToString:AVAudioSessionCategoryPlayAndRecord]){
        [audioSession setCategory:AVAudioSessionCategoryPlayAndRecord error:nil];
        [audioSession setActive:YES error:nil];
    }
    ViewController *vc = [ViewController new];
    [vc answerCall:self.cSession];

}

- (void)hangupAction
{
    [_timeTimer invalidate];
    [self _stopRing];
    AVAudioSession *audioSession = [AVAudioSession sharedInstance];
    [audioSession setCategory:_audioCategory error:nil];
    [audioSession setActive:YES error:nil];
    ViewController *vc = [ViewController new];
    [vc hangupCallWithReason:EMCallEndReasonHangup answerCall:self.cSession];
}

- (void)rejectAction
{
    [_timeTimer invalidate];
    [self _stopRing];
    AVAudioSession *audioSession = [AVAudioSession sharedInstance];
    [audioSession setCategory:_audioCategory error:nil];
    [audioSession setActive:YES error:nil];
    ViewController *vc = [ViewController new];
    [vc  hangupCallWithReason:EMCallEndReasonDecline answerCall:self.cSession];

}

#pragma mark - public

+ (BOOL)canVideo
{
    if([[[UIDevice currentDevice] systemVersion] compare:@"7.0"] != NSOrderedAscending){
        if(!([AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo] == AVAuthorizationStatusAuthorized)){            UIAlertView * alt = [[UIAlertView alloc] initWithTitle:@"No camera permissions" message:@"Please open in \"Setting\"-\"Privacy\"-\"Camera\"." delegate:self cancelButtonTitle:nil otherButtonTitles:@"OK", nil];
            [alt show];
            return NO;
        }
    }
    
    return YES;
}

+ (void)saveBitrate:(NSString*)value
{
    NSScanner* scan = [NSScanner scannerWithString:value];
    int val;
    if ([scan scanInt:&val] && [scan isAtEnd]) {
        NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
        [ud setObject:value forKey:kLocalCallBitrate];
        [ud synchronize];
    }
}

- (void)startTimer
{
    _timeLength = 0;
    _timeTimer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(timeTimerAction:) userInfo:nil repeats:YES];
}

- (void)startShowInfo
{
    if (_callSession.type == EMCallTypeVideo && [self isShowCallInfo]) {
        [self _reloadPropertyData];
        _propertyTimer = [NSTimer scheduledTimerWithTimeInterval:2.0 target:self selector:@selector(_reloadPropertyData) userInfo:nil repeats:YES];
    }
}

//- (void)setNetwork:(EMCallNetworkStatus)status
//{
//    switch (status) {
//        case EMCallNetworkStatusNormal:
//        {
//            _networkLabel.text = @"";
//            _networkLabel.hidden = YES;
//        }
//            break;
//        case EMCallNetworkStatusUnstable:
//        {
//            _networkLabel.text = @"当前网络不稳定";
//            _networkLabel.hidden = NO;
//        }
//            break;
//        case EMCallNetworkStatusNoData:
//        {
//            _networkLabel.text = @"没有通话数据";
//            _networkLabel.hidden = NO;
//        }
//            break;
//        default:
//            break;
//    }
//}

- (void)close
{
    _callSession.remoteVideoView.hidden = YES;
    _callSession = nil;
    _propertyView = nil;
    
    if (_timeTimer) {
        [_timeTimer invalidate];
        _timeTimer = nil;
    }
    
    if (_propertyTimer) {
        [_propertyTimer invalidate];
        _propertyTimer = nil;
    }
    
    [[NSNotificationCenter defaultCenter] postNotificationName:KNOTIFICATION_CALL object:nil];
    
    dispatch_async(dispatch_get_main_queue(), ^{
        [[AVAudioSession sharedInstance] setActive:NO error:nil];
        [self dismissViewControllerAnimated:YES completion:nil];
    });
}

@end

 

以上是关于iOS环信视频聊天的主要内容,如果未能解决你的问题,请参考以下文章

iOS-Senior21-环信

环信IM集成指南iOS端常见问题整理

环信IM集成指南iOS端常见问题整理

集成环信IM入门教程——如何导入及运iOS demo

集成环信IM入门教程——如何导入及运iOS demo

android-使用环信SDK开发即时通信功能及源代码下载