SimpleSample-videochat-ios

Ask tech team
From QuickBlox Developers (API docs, code samples, SDK)
Jump to: navigation, search

Contents

Sources

Project homepage on GIT — https://github.com/QuickBlox/Sample-VideoChat-ios

Download ZIP - https://github.com/QuickBlox/Sample-VideoChat-ios/archive/master.zip


Overview

This sample demonstrates how to work with QuickBlox VideoChat API.
It allows you to organize a video conference between 2 people




Guide: Getting Started with VideoChat API

Creating a QuickBlox account

http://admin.quickblox.com/register

Creating applications in the Admin panel

http://admin.quickblox.com/apps/new

Another helpful source is this 5 minute guide.

Connecting QuickBlox to your application

To get the information on how to connect to the QuickBlox.framework, please, refer to the IOS-how-to-connect-Quickblox-framework page.

Adding Chat to your application

Logging into the Chat

Note: In order to log in to the chat please read the information about Chat login/password formation.

In order to use QuickBlox Chat APIs you must:

  • Create a session & Sign In to QuickBlox OR just create session with user
  • Sign In to QuickBlox Chat

Please follow the lines below:

Create session with User & Sign In to QuickBlox Chat

NSString *userLogin = @"videoChatUser1";
NSString *userPassword = @"videoChatUser1";
 
// Create session with user
QBASessionCreationRequest *extendedAuthRequest = [QBASessionCreationRequest request];
extendedAuthRequest.userLogin = userLogin;
extendedAuthRequest.userPassword = userPassword;
 
[QBAuth createSessionWithExtendedRequest:extendedAuthRequest delegate:self]; 
 
#pragma mark -
#pragma mark QBActionStatusDelegate
 
// QuickBlox queries delegate
- (void)completedWithResult:(Result *)result{
 
    // Create session result
    if(result.success && [result isKindOfClass:QBAAuthSessionCreationResult.class]){
       // You have successfully created the session
       QBAAuthSessionCreationResult *res = (QBAAuthSessionCreationResult *)result;
 
       // Sign In to QuickBlox Chat
       QBUUser *currentUser = [QBUUser user];
       currentUser.ID = res.session.userID; // your current user's ID
       currentUser.password = userPassword; // your current user's password   
 
       // set Chat delegate
       [QBChat instance].delegate = self;
 
       // login to Chat
       [[QBChat instance] loginWithUser:currentUser];
 
    }
}
 
#pragma mark -
#pragma mark QBChatDelegate
 
// Chat delegate
-(void) chatDidLogin{
    // You have successfully signed in to QuickBlox Chat
}

Keep in mind that the QuickBlox Chat is a standard XMPP chat and you need to send presence periodically to remain available. Just create a timer that will send presence every 30 seconds:

[NSTimer scheduledTimerWithTimeInterval:30 target:[QBChat instance] selector:@selector(sendPresence) userInfo:nil repeats:YES];

1 to 1 VideoChat

1 to 1 VideoChat is very easy to set up.

Preparation

In order to use VideoChat API you have to do some extra things.

You need to create an instance of QBVideoChat and set views to where you & your opponent's video stream will be rendered.

QBVideoChat *videoChat = [[QBChat instance] createAndRegisterVideoChatInstance];
videoChat.viewToRenderOpponentVideoStream = opponentVideoView;
videoChat.viewToRenderOwnVideoStream = myVideoView;

When the video chat is no longer needed - just release it:

[[QBChat instance] unregisterVideoChatInstance:self.videoChat];
self.videoChat = nil;

Managing call quality

You can set the fps and other video presets for video chat:

NSMutableDictionary *videoChatConfiguration = [[QBSettings videoChatConfiguration] mutableCopy];
//
[videoChatConfiguration setObject:AVCaptureSessionPresetLow forKey:kQBVideoChatFrameQualityPreset];
[videoChatConfiguration setObject:@10 forKey:kQBVideoChatVideoFramesPerSecond];
//
[QBSettings setVideoChatConfiguration:videoChatConfiguration];

Calling a user

To call a user just use this method:

[QBChat instance].delegate = self;
 
// 3458 - opponent's user ID
[self.videoChat callUser:3458 conferenceType:QBVideoChatConferenceTypeAudioAndVideo];

After this your opponent (user with ID=3458) will be receiving one call request per second for a duration of 15 seconds

#pragma mark -
#pragma mark QBChatDelegate
 
-(void) chatDidReceiveCallRequestFromUser:(NSUInteger)userID withSessionID:(NSString *)_sessionID conferenceType:(enum QBVideoChatConferenceType)conferenceType{
 
}

sessionID - this refers to this video call's session ID. Each particular video call has a unique sessionID. This allows you to have some independent video calls.

If you want to increase the call timeout, increase the values - e.g. to set 20 seconds:

NSMutableDictionary *videoChatConfiguration = [[QBSettings videoChatConfiguration] mutableCopy];
//
[videoChatConfiguration setObject:@20 forKey:kQBVideoChatCallTimeout];
//
[QBSettings setVideoChatConfiguration:videoChatConfiguration];

You can also call with custom parameters:

[QBChat instance].delegate = self;
 
// 3458 - opponent's user ID
[self.videoChat callUser:3458 conferenceType:QBVideoChatConferenceTypeAudioAndVideo customParameters:@{@"Group": @"man"}];
#pragma mark -
#pragma mark QBChatDelegate
 
- (void) chatDidReceiveCallRequestFromUser:(NSUInteger)userID withSessionID:(NSString*)sessionID conferenceType:(enum QBVideoChatConferenceType)conferenceType customParameters:(NSDictionary *)customParameters{
 
}

Accepting the call

To accept call request just use this method:

self.videoChat = [[QBChat instance] createAndRegisterVideoChatInstanceWithSessionID:sessionID];
//
[self.videoChat acceptCallWithOpponentID:videoChatOpponentID conferenceType:videoChatConferenceType];

After this your opponent will receive an accept signal

#pragma mark -
#pragma mark QBChatDelegate
 
-(void) chatCallDidAcceptByUser:(NSUInteger)userID{
 
}

After this the video call will be started. The delegate method below will signal this:

#pragma mark -
#pragma mark QBChatDelegate
 
- (void)chatCallDidStartWithUser:(NSUInteger)userID sessionID:(NSString *)sessionID{
 
}

You can also accept calls with custom parameters:

[self.videoChat acceptCallWithOpponentID:videoChatOpponentID conferenceType:videoChatConferenceType customParameters:@{@"Group":@"man"}];
#pragma mark -
#pragma mark QBChatDelegate
 
-(void) chatCallDidAcceptByUser:(NSUInteger)userID customParameters:(NSDictionary *)customParameters{
 
}

Rejecting the call

To reject the call request, just use this method:

self.videoChat = [[QBChat instance] createAndRegisterVideoChatInstanceWithSessionID:sessionID];
//
[self.videoChat rejectCallWithOpponentID:videoChatOpponentID];
//
// and release video chat instance
[[QBChat instance] unregisterVideoChatInstance:self.videoChat];
self.videoChat = nil;

After this your opponent will receive a reject signal

#pragma mark -
#pragma mark QBChatDelegate
 
-(void) chatCallDidRejectByUser:(NSUInteger)userID{
 
}

Canceling a call

To cancel a call request just use this method:

[self.videoChat cancelCall];

This will cancel callUser: method execution.

Finishing the call

To stop the call request just use this method:

[self.videoChat finishCall];
//
// and release video chat instance
[[QBChat instance] unregisterVideoChatInstance:self.videoChat];
self.videoChat = nil;

After this your opponent will receive a finish signal

#pragma mark -
#pragma mark QBChatDelegate
 
-(void) chatCallDidStopByUser:(NSUInteger)userID status:(NSString *)status{
 
}

Or you can finish it with custom parameters:

[self.videoChat finishCallWithCustomParameters:@{@"Group" : @"man"}];
//
// and release video chat instance
[[QBChat instance] unregisterVideoChatInstance:self.videoChat];
self.videoChat = nil;
#pragma mark -
#pragma mark QBChatDelegate
 
-(void) chatCallDidStopByUser:(NSUInteger)userID status:(NSString *)status customParameters:(NSDictionary *)customParameters{
 
}

There are 3 possible statuses (reasons):

  1. Opponent did not answer - kStopVideoChatCallStatus_OpponentDidNotAnswer
  2. Opponent has finished call with finishCall method - kStopVideoChatCallStatus_Manually
  3. Bad internet connection - kStopVideoChatCallStatus_BadConnection

Muting the microphone

You can disable the microphone during a video call:

self.videoChat.microphoneEnabled = YES/NO;

Changing the Audio route

You can change the Audio route during a video call:

self.videoChat.useHeadphone = YES/NO;

Switching cameras

You can switch between the front and back cameras during a video call:

self.videoChat.useBackCamera = YES/NO;

Enabling the torch

You can enable the torch during a video call:

self.videoChat.cameraFlashEnabled = YES/NO;

1 to 1 AudioChat

Use the same methods and instructions to have an audio chat. To initiate audio call:

[QBChat instance].delegate = self;
 
// 3458 - opponent's user ID
[self.videoChat callUser:3458 conferenceType:QBVideoChatConferenceTypeAudio];

Use custom capture session

QuickBlox iOS SDK takes care of all routine work. You don't need to write low level code while integrating video chat into your application.

But, if you would like to have more control over video chat, you can use some low level video chat APIs.

The next sub sections describe how to use custom audio and video capture sessions. Here is a separate sample branch which shows how to do it - https://github.com/QuickBlox/Sample-VideoChat-ios/tree/customCaptureSession

Custom video capture session

To setup a custom video capture session you simply follow these steps:

  • create an instance of AVCaptureSession
  • setup the input and output
  • implement frames callback and forward all frames to the QuickBlox iOS SDK
  • tell the QuickBlox SDK that you will use your own capture session:

To setup a custom video capture session, setup input and output:

-(void) setupVideoCapture{
    self.captureSession = [[AVCaptureSession alloc] init];
 
    __block NSError *error = nil;
 
    // set preset
    [self.captureSession setSessionPreset:AVCaptureSessionPresetLow];
 
 
    // Setup the Video input
    AVCaptureDevice *videoDevice = [self frontFacingCamera];
    //
    AVCaptureDeviceInput *captureVideoInput = [AVCaptureDeviceInput deviceInputWithDevice:videoDevice error:&error];
    if(error){
        QBDLogEx(@"deviceInputWithDevice Video error: %@", error);
    }else{
        if ([self.captureSession  canAddInput:captureVideoInput]){
            [self.captureSession addInput:captureVideoInput];
        }else{
            QBDLogEx(@"cantAddInput Video");
        }
    }
 
    // Setup Video output
    AVCaptureVideoDataOutput *videoCaptureOutput = [[AVCaptureVideoDataOutput alloc] init];
    videoCaptureOutput.alwaysDiscardsLateVideoFrames = YES;
    //
    // Set the video output to store frame in BGRA (It is supposed to be faster)
    NSString* key = (NSString*)kCVPixelBufferPixelFormatTypeKey;
    NSNumber* value = [NSNumber numberWithUnsignedInt:kCVPixelFormatType_32BGRA];
    NSDictionary* videoSettings = [NSDictionary dictionaryWithObject:value forKey:key];
    [videoCaptureOutput setVideoSettings:videoSettings];
    /*And we create a capture session*/
    if([self.captureSession canAddOutput:videoCaptureOutput]){
        [self.captureSession addOutput:videoCaptureOutput];
    }else{
        QBDLogEx(@"cantAddOutput");
    }
    [videoCaptureOutput release];
 
 
    // set FPS
    int framesPerSecond = 3;
    AVCaptureConnection *conn = [videoCaptureOutput connectionWithMediaType:AVMediaTypeVideo];
    if (conn.isVideoMinFrameDurationSupported){
        conn.videoMinFrameDuration = CMTimeMake(1, framesPerSecond);
    }
    if (conn.isVideoMaxFrameDurationSupported){
        conn.videoMaxFrameDuration = CMTimeMake(1, framesPerSecond);
    }
 
    /*We create a serial queue to handle the processing of our frames*/
    dispatch_queue_t callbackQueue= dispatch_queue_create("cameraQueue", NULL);
    [videoCaptureOutput setSampleBufferDelegate:self queue:callbackQueue];
    dispatch_release(callbackQueue);
 
    // Add preview layer
    AVCaptureVideoPreviewLayer *prewLayer = [[[AVCaptureVideoPreviewLayer alloc] initWithSession:self.captureSession] autorelease];
	[prewLayer setVideoGravity:AVLayerVideoGravityResizeAspectFill];
    CGRect layerRect = [[myVideoView layer] bounds];
	[prewLayer setBounds:layerRect];
	[prewLayer setPosition:CGPointMake(CGRectGetMidX(layerRect),CGRectGetMidY(layerRect))];
    myVideoView.hidden = NO;
    [myVideoView.layer addSublayer:prewLayer];
 
 
    /*We start the capture*/
    [self.captureSession startRunning];
}
 
- (AVCaptureDevice *) cameraWithPosition:(AVCaptureDevicePosition) position{
    NSArray *devices = [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo];
    for (AVCaptureDevice *device in devices) {
        if ([device position] == position) {
            return device;
        }
    }
    return nil;
}
 
- (AVCaptureDevice *) backFacingCamera{
    return [self cameraWithPosition:AVCaptureDevicePositionBack];
}
 
- (AVCaptureDevice *) frontFacingCamera{
    return [self cameraWithPosition:AVCaptureDevicePositionFront];
}

Implement frames callback:

- (void)captureOutput:(AVCaptureOutput *)captureOutput  didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer fromConnection:(AVCaptureConnection *)connection {
 
    // Usually we just forward camera frames to QuickBlox SDK
    // But we also can do something with them before, for example - apply some video filters or so	
    [self.videoChat processVideoChatCaptureVideoSample:sampleBuffer];
}

Tell to QuickBlox iOS SDK that we use our own video capture session:

self.videoChat = [[QBChat instance] createAndRegisterVideoChatInstance];
self.videoChat.viewToRenderOpponentVideoStream = opponentVideoView;
//
// we use own video capture session
self.videoChat.isUseCustomVideoChatCaptureSession = YES;

Custom audio capture session

To setup custom audio capture session you should do the next:

  • rename your UIViewController *.m file to *.mm. Yes, we are going to write some C code!
  • download TPCircularBuffer class from TPCircularBuffer GitHub repository and add it to your project (#import "TPCircularBuffer.h")
  • create an audio 'circular buffer'. It is necessary for manage audio chunks.
  • setup a custom audio capture session and all related callbacks.

Create circular buffer:

#import "TPCircularBuffer.h"
 
#define kBufferLength 32768
#define qbAudioDataSizeForSecods(second) 512*(32*second)
...
TPCircularBuffer circularBuffer;
...
TPCircularBufferInit(&circularBuffer, kBufferLength);

To setup a custom audio capture session:

// Route audio to speaker
//
[[QBAudioIOService shared] routeToSpeaker];
 
// Start processing
//
[[QBAudioIOService shared] setInputBlock:^(AudioBuffer buffer){
    [self.videoChat processVideoChatCaptureAudioBuffer:buffer];
}];
//
[[QBAudioIOService shared] start];

To setup an incoming data delegate:

- (void)didReceiveAudioBuffer:(AudioBuffer)buffer{
 
    // Put audio into circular buffer
    //
    TPCircularBufferProduceBytes(&circularBuffer, buffer.mData, buffer.mDataByteSize);
 
    // Get number of bytes in circular buffer
    //
    int32_t availableBytes;
    TPCircularBufferTail(&circularBuffer, &availableBytes);
 
    // If output block is NIL and we have audio data for 0.5 second
    //
    if([[QBAudioIOService shared] outputBlock] == nil && availableBytes > qbAudioDataSizeForSecods(0.5)){
 
        QBDLogEx(@"Set output block");
        [[QBAudioIOService shared] setOutputBlock:^(AudioBuffer buffer) {
 
            int32_t availableBytesInBuffer;
            void *cbuffer = TPCircularBufferTail(&circularBuffer, &availableBytesInBuffer);
 
            // Read audio data if exist
            if(availableBytesInBuffer > 0){
                int min = MIN(buffer.mDataByteSize, availableBytesInBuffer);
                memcpy(buffer.mData, cbuffer, min);
                TPCircularBufferConsume(&circularBuffer, min);
            }else{
                // No data to play -> mute output
                QBDLogEx(@"No data to play -> mute output");
                [[QBAudioIOService shared] setOutputBlock:nil];
            }
 
            // If there is to much audio data to play -> clear buffer & mute output
            //
            if(availableBytes > qbAudioDataSizeForSecods(3)) {
                QBDLogEx(@"There is to much audio data to play -> clear buffer & mute output");
                TPCircularBufferClear(&circularBuffer);
 
                [[QBAudioIOService shared] setOutputBlock:nil];
            }
        }];
    }
}

Group VideoChat (beta)

With QuickBlox VideoChat SDK it's possible to organise group video chat. In this case you should use the Custom Capture Session, which was described above.

For example, we need to organise a Group Video Chat between 3 users.

Each user should use a Custom Capture Session for Audio & Video.

To call 2 users do the following:

QBVideoChat *videoChat1 = [[QBChat instance] createAndRegisterVideoChatInstance];
[videoChat1 setIsUseCustomVideoChatCaptureSession:YES];
[videoChat1 setIsUseCustomAudioChatSession:YES];
// set view for opponent 1 video stream
videoChat1.viewToRenderOpponentVideoStream = opponent1View;
 
QBVideoChat *videoChat2 = [[QBChat instance] createAndRegisterVideoChatInstance];
[videoChat2 setIsUseCustomVideoChatCaptureSession:YES];
[videoChat2 setIsUseCustomAudioChatSession:YES];
// set view for opponent 2 video stream
videoChat2.viewToRenderOpponentVideoStream = opponent2View;
 
// Call User1
[videoChat callUser:101 conferenceType:QBVideoChatConferenceTypeAudioAndVideo];
 
// Call User2
[videoChat callUser:201 conferenceType:QBVideoChatConferenceTypeAudioAndVideo];

These 2 users will receive call requests through the delegate:

- (void)chatDidReceiveCallRequestFromUser:(NSUInteger)userID withSessionID:(NSString *)sessionID conferenceType:(enum QBVideoChatConferenceType)conferenceType {
 
    // Accept call
    QBVideoChat *videoChat = [[QBChat instance] createAndRegisterVideoChatInstanceWithSessionID:sessionID];
    [videoChat setIsUseCustomVideoChatCaptureSession:YES];
    [videoChat setIsUseCustomAudioChatSession:YES];
    // set view for caller video stream
    videoChat.viewToRenderOpponentVideoStream = opponent2View;
 
    [videoChat acceptCallWithOpponentID:userID conferenceType:conferenceType];
}

The first user will receive an accept signal from these 2 users through the delegate:

- (void)chatCallDidAcceptByUser:(NSUInteger)userID{
}

The next step is to repeat the instructions that were given for setting up a 1-1 Video Chat.

Conclusion

Play with VideoChat code sample, try and integrate it into your apps or combine them with other QuickBlox APIs and create something exciting. As usual, QuickBlox developers assistance team is happy to answer your questions should you have any - just contact us.

Comments

Feel free to comment on this page using the form below.

blog comments powered by Disqus